const memoizedValue = useMemo(() => {
// factory function
}, [obj]);
Imagine obj has several nested props.
In this example with useMemo hook:
obj changes?or
obj and then recompute
the value if some prop have changed, regardless of its reference?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 using Object.is. Relevant condition is emphasized.
Object.is()determines whether two values are the same value. Two values are the same if one of the following holds:
- both
undefined- both
null- both
trueor bothfalse- both strings of the same length with the same characters in the same order
- both the same object (meaning both values reference the same object in memory)
- both
BigIntswith the same numeric value- both
symbolsthat reference the same symbol value- both numbers and
- both +0
- both -0
- both NaN
- or both non-zero, not NaN, and have the same value
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.
React doesn't look more deeply at nested properties when comparing React hook dependencies.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With