React 是否在钩子的依赖数组中应用 shallow/deep 比较?
Does React apply a shallow/deep compare in hooks's dependency array?
const memoizedValue = useMemo(() => {
// factory function
}, [obj]);
假设 obj
有几个嵌套的道具。
在此示例中使用 useMemo 挂钩:
- 如果 reference 到
obj
发生变化,React 会重新计算工厂函数给出的值吗?
或
- 它在
obj
上应用 deep/shallow 比较 然后重新计算
值如果某些道具已更改,无论其引用如何?
Will React recompute the value given by the factory function if the
reference to obj changes?
据我所知,React 使用浅层引用相等性检查。
考虑以下代码:
function App() {
const [c, setC] = React.useState(0);
const [obj, setObj] = React.useState({ prop: 10 });
const forceRender = () => setC((c) => c + 1);
const memoizedValue1 = React.useMemo(() => {
console.log("`obj` dependency updated, recomputing value.");
return obj.prop;
}, [obj]);
const memoizedValue2 = React.useMemo(() => {
console.log("`obj.prop` dependency updated, recomputing value.");
return obj.prop;
}, [obj.prop]);
const immutableHandler = () => {
setObj(() => {
console.log("Immutable update returns new object.");
return { prop: 42 };
});
forceRender();
};
const mutableHandler = () => {
setObj((obj) => {
console.log("Mutable update returns same object with updated property.");
obj.prop = 13; // DON'T DO THIS IN REAL CODE, IT'S A MUTATION!!
return obj;
});
forceRender();
};
return (
<div className="App">
<div>memoizedValue1: {memoizedValue1} - memoizedValue2: {memoizedValue2}</div>
<button type="button" onClick={immutableHandler}>
Immutable Update
</button>
<button type="button" onClick={mutableHandler}>
Mutable Update
</button>
<button type="button" onClick={() => setObj({ prop: 10 })}>
Reset
</button>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
rootElement
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="root" />
memoizedValue1
使用根 obj
对象值作为依赖,而 memoizedValue2
使用嵌套的 obj.prop
对象值作为依赖。一个按钮更新 returns 一个全新的 obj
对象引用,而另一个按钮仅更新 obj.prop
值引用。当整个对象被替换并且是一个新的引用时,注意两个 useMemo
挂钩回调都被调用,但是当只更新嵌套的 prop
值时,只有第二个 useMemo
挂钩回调被调用。
结论
在比较 React 钩子依赖项时,React 不会更深入地查看嵌套属性。
const memoizedValue = useMemo(() => {
// factory function
}, [obj]);
假设 obj
有几个嵌套的道具。
在此示例中使用 useMemo 挂钩:
- 如果 reference 到
obj
发生变化,React 会重新计算工厂函数给出的值吗?
或
- 它在
obj
上应用 deep/shallow 比较 然后重新计算 值如果某些道具已更改,无论其引用如何?
Will React recompute the value given by the factory function if the reference to obj changes?
据我所知,React 使用浅层引用相等性检查。
考虑以下代码:
function App() {
const [c, setC] = React.useState(0);
const [obj, setObj] = React.useState({ prop: 10 });
const forceRender = () => setC((c) => c + 1);
const memoizedValue1 = React.useMemo(() => {
console.log("`obj` dependency updated, recomputing value.");
return obj.prop;
}, [obj]);
const memoizedValue2 = React.useMemo(() => {
console.log("`obj.prop` dependency updated, recomputing value.");
return obj.prop;
}, [obj.prop]);
const immutableHandler = () => {
setObj(() => {
console.log("Immutable update returns new object.");
return { prop: 42 };
});
forceRender();
};
const mutableHandler = () => {
setObj((obj) => {
console.log("Mutable update returns same object with updated property.");
obj.prop = 13; // DON'T DO THIS IN REAL CODE, IT'S A MUTATION!!
return obj;
});
forceRender();
};
return (
<div className="App">
<div>memoizedValue1: {memoizedValue1} - memoizedValue2: {memoizedValue2}</div>
<button type="button" onClick={immutableHandler}>
Immutable Update
</button>
<button type="button" onClick={mutableHandler}>
Mutable Update
</button>
<button type="button" onClick={() => setObj({ prop: 10 })}>
Reset
</button>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
rootElement
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="root" />
memoizedValue1
使用根 obj
对象值作为依赖,而 memoizedValue2
使用嵌套的 obj.prop
对象值作为依赖。一个按钮更新 returns 一个全新的 obj
对象引用,而另一个按钮仅更新 obj.prop
值引用。当整个对象被替换并且是一个新的引用时,注意两个 useMemo
挂钩回调都被调用,但是当只更新嵌套的 prop
值时,只有第二个 useMemo
挂钩回调被调用。
结论
在比较 React 钩子依赖项时,React 不会更深入地查看嵌套属性。