Реагируйте на пользовательские крючки и используйте бесконечные повторные рендеринги

#reactjs #react-hooks #eslint

Вопрос:

 export const useMyCustomHook = () => {
    const uiLoad = useUiLoad(false);
    useEffect(() => {
        // ...
    }, [...]);
}
 

uiLoad является пользовательским крючком (как, очевидно, useMyCustomHook и есть ). Это прекрасно работает, если я не добавляю uiLoad в массив useEffect зависимостей. Если я включу его, он бесконечно перерисовывается.
Вот мой код для uiLoad крючка:

 const baseDispatch = {
    type: SET_LOADING
}

export const useUiLoad = (initial: boolean = false) => {
    const dispatch = useDispatch<Dispatch<UIAction>>();
    const loaded = useRef(false);
    useEffect(() => {
        if (initial amp;amp; !loaded.current) {
            console.log('Called');
            dispatch({
                type: SET_LOADING,
                loadbarShowing: true
            });
            loaded.current= true;
        }
    }, [dispatch, initial])
    return (loading: boolean) => {
        const data: UIAction = {
            ...baseDispatch,
            loadbarShowing: loading
        }
        dispatch(data);
    }
}
 

Насколько я знаю, крючки не меняются при повторной визуализации. Итак, вопросы таковы:

  1. Почему нагрузка меняется при каждом повторном запуске? Используя useWhatChanged инструмент отладчика, я могу обнаружить, что он действительно меняется каждый раз, когда компонент повторно визуализируется. Разве крючки не остаются одинаковыми при каждом рендеринге? Или это не относится к пользовательским крючкам?
  2. Является ли единственным решением здесь подавление предупреждения с помощью // eslint-disable-next-line ?

Комментарии:

1. useUiLoad возвращает новую функцию каждый раз, когда она вызывается, попробуйте запомнить возвращенную функцию в useCallback крючке.

2. @DrewReese Это должно было быть очевидно для меня, и это сработало. Опубликуйте это в качестве ответа

Ответ №1:

Крючки вызываются каждый раз при визуализации компонента. useUiLoad Возвращает новую функцию каждый раз, когда она вызывается. Вы можете вернуть функцию с памятью, чтобы она была стабильной ссылкой.

 export const useUiLoad = (initial: boolean = false) => {
  const dispatch = useDispatch<Dispatch<UIAction>>();
  const loaded = useRef(false);

  useEffect(() => {
    if (initial amp;amp; !loaded.current) {
      console.log('Called');
      dispatch({
        type: SET_LOADING,
        loadbarShowing: true
      });
      loaded.current= true;
    }
  }, [dispatch, initial]);

  return useCallback((loading: boolean) => {
    const data: UIAction = {
      ...baseDispatch,
      loadbarShowing: loading
    }
    dispatch(data);
  }, [dispatch]); // <-- add any other dependencies if necessary
}