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

时间:2019-10-31 08:01:48

标签: javascript reactjs react-hooks

即使依赖项数组具有常量对象,也会触发

useEffect

我尝试提取逻辑并将对象放入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]);

仅当payload更改时才触发。由于payload是一个常数,因此它应该只运行一次并记下无限次。

2 个答案:

答案 0 :(得分:5)

有两个可能导致重新渲染的问题,请注意useEffectdep-array值进行了浅比较

  1. payload是每个渲染上的新对象,因此oldPayload === payload总是false,导致useEffect运行。

  2. 如果dispatch来自第三方库(例如react-redux hook),则可能在每个渲染器上都创建了一个新的dispatch引用,因此oldDispatch === dispatch还是离开false并导致useEffect运行。

要修复此问题,可以将“常量对象”移到外部作用域(它将运行一次),如果传递useCallback,请使用dispatch钩子。

  

来自react-redux docs:的示例在使用分派将回调传递给子组件时,建议使用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;
};
  

注意:dispatch函数的来源没有任何疑问。

答案 1 :(得分:0)

您可以将对象转换为JSON字符串,并在useEffect挂钩中进行比较:

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

请注意,对象键应具有相同的顺序:

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