React Hook useEffect 缺少依赖项:'dispatch'

新手上路,请多包涵

这是我第一次使用 react js,我试图在离开此视图时删除警报,因为我不想在另一个视图上显示它,但如果没有错误,我想保持成功警报显示当我要重定向到另一个视图时

但我在谷歌浏览器上穿了这个 Line 97:6: React Hook useEffect has a missing dependency: 'dispatch'. Either include it or remove the dependency array react-hooks/exhaustive-deps

如果我确实包含调度,我会得到无限循环

const [state, dispatch] = useUserStore();
useEffect(() => {
    let token = params.params.token;
    checktoken(token, dispatch);
  }, [params.params.token]);

  useEffect(() => {
    return () => {
      if (state.alert.msg === "Error") {
        dispatch({
          type: REMOVE_ALERT
        });
      }
    };
  }, [state.alert.msg]);

//response from the api
if (!token_valide || token_valide_message === "done") {
      return <Redirect to="/login" />;
    }

这是 useUserStore

   const globalReducers = useCombinedReducers({
    alert: useReducer(alertReducer, alertInitState),
    auth: useReducer(authReducer, authInitState),
    register: useReducer(registerReducer, registerInitState),
    token: useReducer(passeditReducer, tokenvalidationInitState)
  });
  return (
    <appStore.Provider value={globalReducers}>{children}</appStore.Provider>
  );
};

export const useUserStore = () => useContext(appStore);

原文由 Buk Lau 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.3k
1 个回答

2020 年 9 月 11 日更新

eslint-plugin-react-hooks@4.1.0 及以上版本不再需要此解决方案。

现在 useMemouseCallback 可以安全地接收引用类型作为依赖项。 #19590

 function MyComponent() {
  const foo = ['a', 'b', 'c']; // <== This array is reconstructed each render
  const normalizedFoo = useMemo(() => foo.map(expensiveMapper), [foo]);
  return <OtherComponent foo={normalizedFoo} />
}

这是另一个如何安全地稳定(规范化)回调的示例

const Parent = () => {
    const [message, setMessage] = useState('Greetings!')

    return (
        <h3>
            { message }
        </h3>
        <Child setter={setMessage} />
    )
}

const Child = ({
    setter
}) => {
    const stableSetter = useCallback(args => {
        console.log('Only firing on mount!')
        return setter(args)
    }, [setter])

    useEffect(() => {
        stableSetter('Greetings from child\'s mount cycle')
    }, [stableSetter]) //now shut up eslint

    const [count, setCount] = useState(0)

    const add = () => setCount(c => c + 1)

    return (
        <button onClick={add}>
            Rerender {count}
        </button>
    )
}

Now referential types with stable signature such as those provenients from useState or useDispatch can safely be used inside an effect without triggering exhaustive-deps even when coming from props

编辑 silly-andras-9v1yp


旧答案

dispatch 来自自定义 hook 所以它没有稳定的签名,因此在每次渲染时都会改变(参考相等)。通过将处理程序包装在 useCallback 挂钩中来添加额外的依赖层

   const [foo, dispatch] = myCustomHook()

   const stableDispatch = useCallback(dispatch, []) //assuming that it doesn't need to change

   useEffect(() =>{
        stableDispatch(foo)
   },[stableDispatch])


useCallbackuseMemo 是辅助钩子,主要目的是添加额外的 依赖检查 层以确保同步性。通常你想使用 useCallback 来确保对 prop 你知道如何改变而 React 不会改变的稳定签名。

A function (引用类型)通过 props 例如

const Component = ({ setParentState }) =>{
    useEffect(() => setParentState('mounted'), [])
}

假设您有一个子组件,在安装时必须在父组件中设置一些状态(不常见),上面的代码将在 useEffect 中生成未声明依赖项的警告,所以让我们声明 setParentState 作为 React 检查的依赖项

const Component = ({ setParentState }) =>{
    useEffect(() => setParentState('mounted'), [setParentState])
}

现在,这种效果在每次渲染时都会运行,不仅在安装时,而且在每次更新时。发生这种情况是因为 setParentStatefunction 每次调用函数 Component 时都会重新创建它。你知道 setParentState 不会改变它的签名超时,所以告诉 React 是安全的。通过将原始助手包装在 useCallback 中,您就是这样做的(添加另一个依赖检查层)。

 const Component = ({ setParentState }) =>{
   const stableSetter = useCallback(() => setParentState(), [])

   useEffect(() => setParentState('mounted'), [stableSetter])
}

你去吧。现在 React 知道 stableSetter 不会在生命周期内改变它的签名,因此效果不需要太不必要地运行。

附带说明 useCallback 它也像 useMemo 一样使用,以优化昂贵的函数调用(记忆)。

useCallback 的两个主要目的是

  • 优化依赖引用相等的子组件以防止不必要的渲染。 字体

  • 记住昂贵的计算

原文由 Dupocas 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进