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
是一个常数,所以它应该只运行一次,并记录无限次。
有两个问题可能会导致重新渲染,请注意useEffect
与dep-array
值进行了浅比较:
-
payload
在每次渲染中都是一个新对象,因此oldPayload === payload
始终为false
,导致useEffect
运行。 -
如果
dispatch
来自第三方库(如react redux hook(,则它可能会在每个渲染上生成新的dispatch
引用,因此oldDispatch === dispatch
再次离开false
并导致useEffect
运行。
要修复它,可以将"常量对象"移动到外部作用域(将运行一次(,如果传递dispatch
,则使用useCallback
钩子。
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;
};
注意:没有任何迹象表明
dispatch
函数来自何处。
您可以将对象转换为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