简体   繁体   English

useEffect 导致具有恒定依赖性的无限循环

[英]useEffect causing infinite looping with constant dependency

useEffect is getting triggered even though the dependency array has constant object.即使依赖数组具有常量 object, useEffect也会被触发。

I tried extracting the logic and put the object in useState我尝试提取逻辑并将 object 置于useState

const payload = {
    limit: 5,
    offset: 0,
    filterBy: 'All',
};

useEffect(() => {
    const defaultPayload = {
        limit: 10,
        offset: 0,
        filterBy: 'All',
    };
        dispatch({ type: RANDOM_CONST, payload: payload || defaultPayload });
}, [dispatch, payload]);

It should trigger only when payload changes.它应该仅在payload更改时触发。 Since, payload is a constant, it should just run once and note infinite times.由于payload是一个常数,它应该只运行一次并注意无限次。

There are two problems that may cause the re-render, notice that the useEffect makes a shallow comparison with the dep-array values:有两个问题可能会导致重新渲染,请注意useEffectdep-array值进行了浅比较

  1. payload is a new object on every render, therefore oldPayload === payload always false , causes the useEffect to run. payload在每次渲染时都是一个新的 object,因此oldPayload === payload总是false ,导致useEffect运行。

  2. If dispatch comes from 3rd party library (like react-redux hook ), it might be making a new dispatch reference on every render, therefore again oldDispatch === dispatch is aways false and causes useEffect to run.如果dispatch来自 3rd 方库(如react-redux 挂钩),它可能会在每个渲染上创建一个新的dispatch引用,因此oldDispatch === dispatch再次为false并导致useEffect运行。

To fix it, you can move the "constant object" to the outer scope (which will run once), and use useCallback hook if you passing the dispatch .要修复它,您可以将“常量对象”移动到外部 scope (它将运行一次),并在传递dispatch时使用useCallback钩子。

Example from react-redux docs: When passing a callback using dispatch to a child component, it is recommended to memoize it with useCallback , since otherwise child components may render unnecessarily due to the changed reference.来自react-redux文档的示例:当使用 dispatch 向子组件传递回调时,建议使用useCallback来记忆它,否则子组件可能会由于引用的更改而不必要地呈现。

const payload = {
  limit: 5,
  offset: 0,
  filterBy: 'All'
};

const App = () => {
  //                   v Memoize it if passing as a callback,
  //                     check in library docs if there is a new instance
  //                     on every render
  const dispatch = useDispatch();

  useEffect(() => {
    dispatch({ type: RANDOM_CONST, payload });
  }, []);

  return;
};

Note: There is no indication in question where the dispatch function comes from.注意:没有迹象表明dispatch function 来自何处。

You can convert the objects to JSON strings and compare them inside your useEffect hook:您可以将对象转换为 JSON 字符串并在您的 useEffect 挂钩中进行比较:

JSON.stringify(oldValue) === JSON.stringify(newValue) // true

Note that object keys should have the same order:请注意,object 密钥应具有相同的顺序:

JSON.stringify({a: 1, b: 2}) === JSON.stringify({a: 1, b: 2}) // true
JSON.stringify({a: 1, b: 2}) === JSON.stringify({b: 2, a: 1}) // false

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM