const memoizedValue = useMemo(() => {
// factory function
}, [obj]);
Imagine obj
has several nested props.
In this example with useMemo hook:
- Will React recompute the value given by the factory function if the reference to
obj
changes?
or
- It applies a deep/shallow compare on
obj
and then recompute the value if some prop have changed, regardless of its reference?
CodePudding user response:
Will React recompute the value given by the factory function if the reference to obj changes?
From what I know and understand, React uses shallow reference equality checks.
Consider the following code:
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
is using the root obj
object value as a dependency while memoizedValue2
uses the nested obj.prop
object value as a dependency. One button updates and returns an entirely new obj
object reference while the other only updates the obj.prop
value reference. When the entire object is replaced and is a new reference notice that both useMemo
hook callbacks are invoked, but when only updating the nested prop
value that only the second useMemo
hook callback is invoked.
Conclusion
React doesn't look more deeply at nested properties when comparing React hook dependencies.