reactjs - 具有调度函数的 useSelector 和 UseEffect 由于不更新状态而创建循环

标签 reactjs react-redux react-hooks infinite-loop dispatch

我正在尝试开发一个 React 应用程序,该应用程序使用 Hooks 显示项目列表,但正在发生无限循环。我认为该状态未被识别为已更新,但我无法说出原因。

我在文档中看到,我应该在 useEffect 函数上添加依赖项,但是当我删除对 useEffect 的依赖项时,它解决了问题。此外,这不是文档建议这样做,他们建议将所有依赖项放在列表中。

代码和框在这里:https://codesandbox.io/s/react-listing-forked-6sd99 如果我取消注释 Dashboard.ts 第 30 行,则可以看到无限循环,这是调用 dispatch 函数的行(并且codesandbox也会卡住几秒钟)。

useSelector 和 useEffect 函数如下,位于 Dashboard.tsx 文件中:

  const catalog = useSelector<RootState, MetricState>(
    (state) => state.fetchMetrics
  );
  console.log(catalog);

  const dispatch = useDispatch();

  const classes = useStyles();
  useEffect(() => {
    // dispatch(appReducer.actionCreators.fetchMetrics());
  },[catalog, dispatch]));

模拟数据如下,位于apiCreators.js文件中

export function fetchMetrics() {
  const action = {
    type: ACTION_TYPES.FETCH_METRICS,
    payload: []
  };
  return fetchMetricsCall(action);

const fetchMetricsCall = (action) => async (dispatch) => {
  try {
    dispatch({
      type: action.type,
      payload: {
        metrics: [
          {
            name: "one",
            owner: {
              team: "test"
            }
          },
          {
            name: "one",
            owner: {
              team: "test"
            }
          }
        ] //contains the data to be passed to reducer
      }.metrics
    });
  } catch (e) {
    dispatch({
      type: ACTION_TYPES.FAILURE,
      payload: console.log(e) //TODO: fix return type
    });
  }
};

最佳答案

主要问题是在此处找到的[catalog,dispatch]内的catalog:

useEffect(() => {
    // dispatch(appReducer.actionCreators.fetchMetrics());
  },[catalog, dispatch]));

问题在于 dispatch(appReducer.actionCreators.fetchMetrics()) 导致 state.fetchMetrics(又名目录) 更新(这是一个对象),并且在比较对象/数组时,javascript 是“奇怪的”。

让我们看看这个:

let x = {a: 0}
let y = {a: 0}
let z = x

console.log(x === y) // this is FALSE
console.log(x === x) // this is TRUE
console.log(z === x) // this is TRUE

这篇文章更好地探讨了这个问题:http://adripofjavascript.com/blog/drips/object-equality-in-javascript.html

每当状态发生变化时,

useEffect 就会执行类似 if(oldState.catalog !== newState.catalog) {...rerender component} 的操作(我觉得这样可能真的不准确,但我希望它有助于说明正在发生的事情)。因此,组件重新渲染并对 dispatch 进行新的调用,这会更新状态,并且由于 useEffect 内的依赖项之一是一个对象,因此不可能进行更新告诉 useEffect “停止重新渲染”。

有多种方法可以解决此问题,但您不应该需要 [catalog,dispatch] 内的 catalog。只需删除它似乎就可以解决问题?

关于reactjs - 具有调度函数的 useSelector 和 UseEffect 由于不更新状态而创建循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67165650/

相关文章:

reactjs - 引用错误: undefinedcreateProvider is not defined

javascript - 如何将 setTimeout() 与 React Hooks useEffect 和 setState 一起使用?

javascript - 以编程方式导航到不同的路线并传递查询

javascript - 每次部署新版本的 Web 应用程序时如何清理浏览器缓存?

javascript - Redux 存储未在全局范围内更新

javascript - 如何使用 useEffect 的异步返回值作为 useState 中的默认值?

javascript - 在 HOC 中使用 useState/Hooks 使用react导致错误 "Hooks can only be called inside of the body of a function component"

javascript - 如何为 react/redux 创建加载器旋转

reactjs - React-Redux:如何从 'anywhere' 访问存储而不导入它?

javascript - mapStateToProps 赋值的最佳实践