PureComponent浅比较(16.8.6)

React PureComponent 浅比较源码解析

ReactFiberClassComponent.js

1
2
3
4
5
6
7
8
9
// packages/react-reconciler/src/ReactFiberClassComponent.js

// 判断此组件是否为 PureComponent
// 对props跟state的前后状态做浅比较(shallowEqual)
if (ctor.prototype && ctor.prototype.isPureReactComponent) {
return (
!shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState)
);
}

shallowEqual.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// packages/shared/shallowEqual.js

import is from './objectIs';

function shallowEqual(objA: mixed, objB: mixed): boolean {
// 基本数据类型判断值是否相同,引用数据类型判断是否是同一个引用
if (is(objA, objB)) {
return true;
}

// 如果两个对象都不是 Object,返回false
if (
typeof objA !== 'object'
|| objA === null
|| typeof objB !== 'object'
|| objB === null
) {
return false;
}

// 比较对象
// 首先对key的长度进行对比
const keysA = Object.keys(objA);
const keysB = Object.keys(objB);

// key长度不等,不相等,返回false
if (keysA.length !== keysB.length) {
return false;
}

// key长度相等,循环比较
for (let i = 0; i < keysA.length; i++) {
// 用 hasOwnProperty 方法判断 objB 是否存在 objA 的 key
// 对相同key的value进行is函数比较,只比较了第一层,没有对深层嵌套的数据做处理,返回结果
if (
!hasOwnProperty.call(objB, keysA[i]) ||
!is(objA[keysA[i]], objB[keysA[i]])
) {
return false;
}
}

return true;
}

objectIs.js:

1
2
3
4
5
6
7
8
9
10
// packages/shared/objectIs.js

// (x === y && (x !== 0 || 1 / x === 1 / y)) 区分+0和-0, +0 === -0 为true,不能直接用===判断
// (x !== x && y !== y) 区分NaN,NaN === NaN 为false,NaN不等于自身,不能直接用===判断
// 如果x、y为引用数据类型,仅对比它们的引用值,如果指向同一个内存地址,则直接认为相等
function is(x: any, y: any) {
return (
(x === y && (x !== 0 || 1 / x === 1 / y)) || (x !== x && y !== y)
);
}