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.
Introduction
When learning React PureComponent, you encounter the statement that its
shouldComponentUpdateperforms 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
shouldComponentUpdatecontains:
<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
shallowEqualis:
<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.isfixes 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.isreturns 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.isto 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.ison 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.
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.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.