Frontend Development 7 min read

Why React PureComponent’s Shallow Comparison Fails on Nested Objects

This article explains the shallow comparison used by React's PureComponent, details the implementation of shallowEqual and Object.is, and shows why such a shallow check cannot correctly compare nested objects, providing code examples and clear explanations.

Tencent IMWeb Frontend Team
Tencent IMWeb Frontend Team
Tencent IMWeb Frontend Team
Why React PureComponent’s Shallow Comparison Fails on Nested Objects

Introduction

When learning React PureComponent, you encounter the statement that its

shouldComponentUpdate

performs a shallow comparison of props and state, which does not work for nested objects. This article explains what a shallow comparison is and why it fails for nested structures.

shallowEqual

In React, the source of

shouldComponentUpdate

contains:

<code>if (this._compositeType === CompositeTypes.PureClass) {
  shouldUpdate = !shallowEqual(prevProps, nextProps) || !shallowEqual(inst.state, nextState);
}</code>

Thus PureComponent uses a shallow comparison of props and state. The implementation of

shallowEqual

is:

<code>const hasOwn = Object.prototype.hasOwnProperty;
function is(x, y) {
  if (x === y) {
    return x !== 0 || y !== 0 || 1 / x === 1 / y;
  } else {
    return x !== x && y !== y;
  }
}
export default function shallowEqual(objA, objB) {
  if (is(objA, objB)) return true;
  if (typeof objA !== 'object' || objA === null ||
      typeof objB !== 'object' || objB === null) {
    return false;
  }
  const keysA = Object.keys(objA);
  const keysB = Object.keys(objB);
  if (keysA.length !== keysB.length) return false;
  for (let i = 0; i < keysA.length; i++) {
    if (!hasOwn.call(objB, keysA[i]) ||
        !is(objA[keysA[i]], objB[keysA[i]])) {
      return false;
    }
  }
  return true;
}</code>

Object.is()

Before diving into

shallowEqual

, understand

Object.is()

, a function that determines whether two values are the same. It differs from

==

(which performs type coercion) and

===

(which fails for +0 vs -0 and NaN).

Object.is

fixes these edge cases.

<code>function is(x, y) {
  if (x === y) {
    return x !== 0 || 1 / x === 1 / y;
  } else {
    return x !== x && y !== y;
  }
}</code>
Object.is

returns true for:

both undefined

both null

both true or both false

identical strings

the same object reference

numbers that are the same, including +0, -0, and NaN

Analyzing shallowEqual

The function first uses

Object.is

to compare primitive values. If either argument is not an object, it returns false. For objects, it compares the sets of keys; if the key counts differ, it returns false. Then it iterates over the keys, ensuring each key exists in the other object and that the corresponding values are equal according to

Object.is

. Because the value comparison is shallow, nested objects are compared by reference, leading to unexpected results when the nested structures differ.

Conclusion

Shallow comparison cannot handle nested objects because it only checks the top‑level keys and uses

Object.is

on the values. If a value itself is an object, the comparison is by reference, not by deep structure, which explains why PureComponent’s shallow check fails for nested data.

frontendJavaScriptReactPureComponentObject.isshallowEqual
Tencent IMWeb Frontend Team
Written by

Tencent IMWeb Frontend Team

IMWeb Frontend Community gathering frontend development enthusiasts. Follow us for refined live courses by top experts, cutting‑edge technical posts, and to sharpen your frontend skills.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.