Skip to Content

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.

References:
comments powered by Disqus