Как отслеживать ссылку на объект в useEffect?

Я создаю несколько хуков API, и у меня проблемы со свойством deps. Я хочу повторно вызывать useEffect при изменении содержимого deps, вместо этого я работаю в вечном цикле. deps может быть неопределенным или any[]

export const useReader = <TResponseData>({ url, deps, options }: TypeUseReader<TResponseData>) => {
    const [data, setData] = useState<TResponseData | null>(null);
    const [isLoading, setIsLoading] = useState<boolean>(false);
    const [error, setError] = useState<number | null >(null);

    async function fetchData(newUrl?: string) {}

    useEffect(() => {
       // ..fetch
    // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [url, deps]); // HERE, deps are forever loop

    return {
        data,
        isLoading,
        error,
        fetchData
    };
};

Вот как я его использую:

 return useReader<FOO>(
        {
            url: 'URL_PLACEHOLDER',
            deps: [anything] /* FIXME: deps enters FOREVER LOOP */
        }
    );

Что я пробовал:

[deps ?? []] и ...[deps ?? []] и deps - все это создает вечный цикл

Вы пытались заменить [options?.deps ?? []] как зависимость в useEffect на: options ? Я подозреваю, что обертывание всего этого массивом заставляет его переоценивать новый объект каждый раз, когда он проверяется.

Nir Alfasi 16.04.2023 23:06

@NirAlfasi Я переключился на использование deps напрямую, чтобы удалить options опору из уравнения, и обновил код. Но я все еще получаю вечный цикл

Mufasa 16.04.2023 23:13
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
0
2
54
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Проблема в том, что когда вы вызываете useReader с deps в качестве литерала массива, каждый раз создается новый массив, поэтому useEffect правильно определяет изменение значения.

Вообще говоря, есть два способа справиться с этим.

Вы можете сделать это ответственным за вызывающую сторону — укажите в useReader интерфейсе, что она принимает одно dep значение типа unknown. Если вызывающая сторона хочет пройти через массив значений, они должны быть стабилизированы, например.

const dep = useMemo(() => [val1, val2], [val1, val2]);
return useReader<FOO>(
        {
            url: 'URL_PLACEHOLDER',
            isSuspended: false,
            initialValue: foo,
            dep   /* only changes if val1 or val2 has changed */
        }
    );

Проще и гибче принять массив deps (напечатанный как unknown[]) и просто распределить элементы массива после других зависимостей, которые вы передаете useEffect:

    useEffect(() => {
        if (!isSuspended) {
            fetchData();
        }
    // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [isSuspended, url, ...(deps ?? [])]);

Различные линтеры расстраиваются из-за этого, но это не проблема в том, что касается механизма перехвата.

Спасибо. Это работает! Теперь я ясно понимаю, почему у него был вечный цикл, я каждый раз создавал новый массив. Но почему ...(deps ?? []) тоже не вызывает бесконечный цикл? Деструктуризация возвращает новое значение. ИЛИ это потому, что деструктуризация не изменяет ссылки?

Mufasa 16.04.2023 23:41

Вы не поделились определением TypeUseReader<TResponseData>, поэтому я не уверен, считаете ли вы deps необязательным. Если deps не определено, то deps ?? [] просто вернется к пустому массиву. Распространение пустого массива не влияет на содержимое зависимостей useEffect, и только содержимое определяет, будет ли эффект повторно запущен. Если вам требуется deps в качестве параметра для useReader, вы можете просто использовать ...deps вместо ...(deps ?? [])

motto 16.04.2023 23:44
deps необязательно, но если я правильно понял ваше объяснение. Это не проблема, потому что распространение пустого массива не влияет на массив зависимостей useEffect.
Mufasa 16.04.2023 23:48

Ваше понимание правильное (или, по крайней мере, мое понимание вашего понимания :-)

motto 16.04.2023 23:49

Другие вопросы по теме