0%

React源码之Component和PureComponent区别

先说结论

PureComponent 会比较前后 props 对象的第一层是否相等,如果不相等就会更新,面 Compoent 是只有要变化就会更新。

源码追溯

ReactComponentPureComponent 定义在源码目录的packages/react/src/ReactBaseClasses.js 里面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function ComponentDummy() {}
ComponentDummy.prototype = Component.prototype;

/**
* Convenience component with default shallow equality check for sCU.
*/
function PureComponent(props, context, updater) {
this.props = props;
this.context = context;
// If a component has string refs, we will assign a different object later.
this.refs = emptyObject;
this.updater = updater || ReactNoopUpdateQueue;
}

const pureComponentPrototype = (PureComponent.prototype = new ComponentDummy());
pureComponentPrototype.constructor = PureComponent;
// Avoid an extra prototype jump for these methods.
Object.assign(pureComponentPrototype, Component.prototype);
pureComponentPrototype.isPureReactComponent = true;

源码定义里面 ComponentPureComponent 只有一个区别,就是 PureComponent 的原型上有一个 isPureReactComponenttrue 的属性。

通过全局查找,发现只有在 packages/react-reconciler/src/ReactFiberClassComponent.js 中有使用到

react-reconciler 这个目录是 React 内部进行调度的过程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function checkShouldComponentUpdate(
workInProgress,
ctor,
oldProps,
newProps,
oldState,
newState,
nextContext,
) {
const instance = workInProgress.stateNode;
if (typeof instance.shouldComponentUpdate === 'function') {...
}

if (ctor.prototype && ctor.prototype.isPureReactComponent) {
return (
!shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState)
);
}

return true;
}

再看看 shallowEqual 方法的内部, 定义在 packages/shared/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
function shallowEqual(objA: mixed, objB: mixed): boolean {
// is 在packages/shared/objectIs.js中,这里就直接贴过来了
// 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
// );
// }
// 这里其实就是Object.is的polyfill
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;
}

// Test for A's keys different from B.
for (let i = 0; i < keysA.length; i++) {
if (
!hasOwnProperty.call(objB, keysA[i]) ||
!is(objA[keysA[i]], objB[keysA[i]])
) {
return false;
}
}

return true;
}

shallowEqual 其实就是只对对象的第一导进行比较, shallowEqual({count: 1}, {count: 1}) === true

总结

PureComponent 会比较前后 props 对象的第一层是否相等,如果不相等就会更新,面 Compoent 是只有要变化就会更新。