useSelector 和 UseEffect 与调度函数创建循环,由于未更新状态



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

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

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

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 (aka catalog)更新(这是一个对象),而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。简单地删除它似乎可以解决问题?

最新更新