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

Buk*_*Lau 28 reactjs react-hooks

这是我第一次使用 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" />;
    }
Run Code Online (Sandbox Code Playgroud)

这是 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);
Run Code Online (Sandbox Code Playgroud)

Dup*_*cas 39

dispatch来自自定义,hook因此它没有稳定的签名,因此会在每次渲染时发生变化(引用相等)。通过将处理程序包装在useCallback钩子中来添加额外的依赖层

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

   useEffect(() =>{
        stableDispatch(foo)
   },[stableDispatch])
Run Code Online (Sandbox Code Playgroud)

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

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

const Component = ({ setParentState }) =>{
    useEffect(() => setParentState('mounted'), [])
}
Run Code Online (Sandbox Code Playgroud)

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

const Component = ({ setParentState }) =>{
    useEffect(() => setParentState('mounted'), [setParentState])
}
Run Code Online (Sandbox Code Playgroud)

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

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

   useEffect(() => setParentState('mounted'), [stableSetter])
}
Run Code Online (Sandbox Code Playgroud)

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

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

的两个主要目的useCallback

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

  • 记住昂贵的计算

更新 09/11/2020

不再需要此解决方案es-lint-plugin-react-hooks@4.1.0

现在useMemo并且useCallback可以安全地接收引用类型作为依赖项。#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} />
}
Run Code Online (Sandbox Code Playgroud)

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

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>
    )
}
Run Code Online (Sandbox Code Playgroud)

现在具有稳定签名的引用类型,例如那些来自useStateuseDispatch可以安全地在效果内使用,exhaustive-deps即使来自效果也不会触发props

编辑silly-andras-9v1yp

  • 对我来说,eslint 仍然警告缺少依赖项“dispatch”,尽管它是新版本 (3认同)
  • 会起作用,但我认为OP应该从源头解决它,而不是OP将在很多地方使用调度的地方。 (2认同)