React Hook useEffect 缺少依赖项:'dispatch' [英] React Hook useEffect has a missing dependency: 'dispatch'

查看:50
本文介绍了React Hook useEffect 缺少依赖项:'dispatch'的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

但我在谷歌浏览器上穿这个第 97:6 行:React Hook useEffect 缺少依赖项:'dispatch'.要么包括它要么删除依赖数组 react-hooks/exhaustive-deps

如果我确实包含 dispatch 我会无限循环

const [state, dispatch] = useUserStore();useEffect(() => {让令牌 = params.params.token;检查令牌(令牌,调度);}, [params.params.token]);useEffect(() => {返回 () =>{如果(state.alert.msg ===错误"){派遣({类型:REMOVE_ALERT});}};}, [state.alert.msg]);//来自api的响应如果(!token_valide || token_valide_message ===完成"){return <Redirect to="/login"/>;}

这是 useUserStore

 const globalReducers = useCombinedReducers({警报:useReducer(alertReducer,alertInitState),身份验证:useReducer(authReducer,authInitState),注册:useReducer(registerReducer, registerInitState),令牌:useReducer(passeditReducer,tokenvalidationInitState)});返回 (<appStore.Provider value={globalReducers}>{children}</appStore.Provider>);};export const useUserStore = () =>使用上下文(应用商店);

解决方案

dispatch 来自自定义 hook,因此它没有稳定的签名,因此会在每个渲染(引用相等).通过将处理程序包装在 useCallback 钩子

中来添加额外的依赖层

 const [foo, dispatch] = myCustomHook()const stableDispatch = useCallback(dispatch, [])//假设不需要改变useEffect(() =>{稳定调度(富)},[stableDispatch])


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

例如通过props传递的function(引用类型)

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

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

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

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

const 组件 = ({ setParentState }) =>{const stableSetter = useCallback(() => setParentState(), [])useEffect(() => setParentState('mounted'), [stableSetter])}

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

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

useCallback 的两个主要目的是

  • 优化依赖引用相等的子组件,防止不必要的呈现.

    This is my first time working with react js , im trying to remove the alert when leaving this view cause i don't want to show it on the other view but in case that there is no error i want to keep the success alert to show it when i'm gonna redirect to the other view

    but im getting this wearning on google chrome Line 97:6: React Hook useEffect has a missing dependency: 'dispatch'. Either include it or remove the dependency array react-hooks/exhaustive-deps

    if i did include dispatch i get infinite loop

    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" />;
        }
    

    this is 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);
    

    解决方案

    dispatch comes from a custom hook so it doesn't have an stable signature therefore will change on each render (reference equality). Add an aditional layer of dependencies by wrapping the handler inside an useCallback hook

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


    useCallback and useMemo are helper hooks with the main purpose off adding an extra layer of dependency check to ensure synchronicity. Usually you want to work with useCallback to ensure a stable signature to a prop that you know how will change and React doesn't.

    A function(reference type) passed via props for example

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

    Lets assume you have a child component which uppon mounting must set some state in the parent (not usual), the above code will generate a warning of undeclared dependency in useEffect, so let's declare setParentState as a dependency to be checked by React

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

    Now this effect runs on each render, not only on mounting, but on each update. This happens because setParentState is a function which is recreated every time the function Component gets called. You know that setParentState won't change it's signature overtime so it's safe to tell React that. By wrapping the original helper inside an useCallback you're doing exactly that (adding another dependency check layer).

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

    There you go. Now React knows that stableSetter won't change it's signature inside the lifecycle therefore the effect do not need too run unecessarily.

    On a side note useCallback it's also used like useMemo, to optmize expensive function calls (memoization).

    The two mai/n purposes of useCallback are

    • Optimize child components that rely on reference equality to prevent unnecessary renders. Font

    • Memoize expensive calculations

    UPDATE 09/11/2020

    This solution is no needed on es-lint-plugin-react-hooks@4.1.0 and above.

    Now useMemo and useCallback can safely receive referential types as dependencies.#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} />
    }
    

    Here is another example of how to safely stabilize(normalize) a callback

    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

    这篇关于React Hook useEffect 缺少依赖项:'dispatch'的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆