首页 > 解决方案 > React Custom Hooks 和 useEffect 无限重新渲染

问题描述

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

uiLoad是一个自定义钩子(显然,是useMyCustomHook)。如果我不添加uiLoaduseEffect依赖数组,这很好。如果我确实包含它,它会无限重新渲染。这是我的uiLoad钩子代码:

const baseDispatch = {
    type: SET_LOADING
}

export const useUiLoad = (initial: boolean = false) => {
    const dispatch = useDispatch<Dispatch<UIAction>>();
    const loaded = useRef(false);
    useEffect(() => {
        if (initial && !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. 为什么每次重新渲染时 uiLoad 都会发生变化?使用useWhatChanged调试器工具,我发现它确实在每次组件重新渲染时都会发生变化。钩子不是每次渲染都保持不变吗?或者这不适用于自定义钩子?

  2. 这里唯一的解决方案是使用 抑制警告// eslint-disable-next-line吗?

标签: reactjsreact-hookseslint

解决方案


每次渲染组件时都会调用钩子。每次调用时都会useUiLoad返回一个函数。您可以返回一个记忆函数,因此它是一个稳定的参考。

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

  useEffect(() => {
    if (initial && !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
}

推荐阅读