How React Compares Dependencies
Q: How does React compare dependencies for useEffect
, useMemo
, and other Hooks?
A: It uses Object.is
, which differs distinctly in behavior from both ==
and ===
. I went searching in the React codebase and here is where
Object.is
is referenced (with a polyfill): shared/objectIs.js
/**
* inlined Object.is polyfill to avoid requiring consumers ship their own
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
*/
function is(x: any, y: any) {
return (
(x === y && (x !== 0 || 1 / x === 1 / y)) || (x !== x && y !== y) // eslint-disable-line no-self-compare
);
}
const objectIs: (x: any, y: any) => boolean =
typeof Object.is === "function" ? Object.is : is;
export default objectIs;
and where the comparison logic for dependencies lies : react-reconciler/src/ReactFiberHooks.new.js
for (let i = 0; i < prevDeps.length && i < nextDeps.length; i++) {
if (is(nextDeps[i], prevDeps[i])) {
continue;
}
return false;
}
return true;
Object.is
compares references, so adding a function declared inside the body of a React component as a dependency to useEffect
will cause this effect to be re-run every time regardless of whether props/state referenced by the function have changed. To avoid this, you could call useCallback
to memoize the function, although you should only do this if other options are not possible.