When I went to the interview last week, THE interviewer remembered how to compare props in PureComponent, and I blurted out a light comparison. Then the interviewer asked me what the light comparison was, but I didn’t give an answer.
Take advantage of the weekend, and look at the source code is how to achieve.
Class component Props comparison
ShouldComponentUpdate (); shouldComponentUpdate (); shouldComponentUpdate (); shouldComponentUpdate ();
// ReactBaseClasses.js
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;
Copy the code
I thought the shouldComponentUpdate method would be implemented by default when declaring PureComponent, but there isn’t one.
Next look at the call to the shouldComponentUpdate method.
// ReactFiberClassComponent.js
function checkShouldComponentUpdate(workInProgress, ctor, oldProps, newProps, oldState, newState, nextContext,) {
const instance = workInProgress.stateNode;
// If the utility implements shouldComponentUpdate, return the result of calling it
if (typeof instance.shouldComponentUpdate === 'function') {
const shouldUpdate = instance.shouldComponentUpdate(
newProps,
newState,
nextContext,
);
return shouldUpdate;
}
// Shallow contrast when PureReactComponent
if (ctor.prototype && ctor.prototype.isPureReactComponent) {
return(! shallowEqual(oldProps, newProps) || ! shallowEqual(oldState, newState) ); }return true;
}
Copy the code
We don’t actually write a shouldComponentUpdate method for the PureReactComponent. Instead, we return a shallower comparison when comparing.
The shallow contrast is all in the shallowEqual method.
ShallowEqual light contrast
// shallowEqual.js
function shallowEqual(objA: mixed, objB: mixed) :boolean {
// The same object returns true
if (Object.is(objA, objB)) {
return true;
}
// Is not an object or returns false for null
if (
typeofobjA ! = ='object' ||
objA === null ||
typeofobjB ! = ='object' ||
objB === null
) {
return false;
}
const keysA = Object.keys(objA);
const keysB = Object.keys(objB);
// Return false if the number of keys varies
if(keysA.length ! == keysB.length) {return false;
}
// Return false for different keys
for (let i = 0; i < keysA.length; i++) {
if (
!hasOwnProperty.call(objB, keysA[i]) ||
!Object.is(objA[keysA[i]], objB[keysA[i]])
) {
return false; }}return true;
}
Copy the code
The shallowEqual method is pretty simple
- First determine whether the two are the same object.
- Determine whether the two values are not
object
Or forNull.
- Comparing the two
key
The length of the. - To determine both
key
Whether the corresponding values are the same.
The original principle is such a simple comparison, if I can spit source code during the interview, will the salary be higher?
A shallow comparison of function components
A shallow comparison of function components is implemented using the React. Memo method.
// ReactMemo.js
export function memo<Props> (type: React$ElementType, compare? : (oldProps: Props, newProps: Props) => boolean,) {
const elementType = {
$$typeof: REACT_MEMO_TYPE,
type,
compare: compare === undefined ? null : compare,
};
return elementType;
}
Copy the code
The react. memo method also supports passing compare as the second argument.
$$typeOF is ReactElement for REACT_MEMO_TYPE.
The react. memo component is a little more complicated to create. Internally, it is actually defined as two types of Fiber nodes, since a second custom compare function can be passed in.
- No incoming
compare
Function forSimpleMemoComponent
. - Custom is passed in
compare
Function forMemoComponent
.
But the actual comparison for Props is the same, and the default is to call the shallowEqual method to compare.
updateSimpleMemoComponent
if (
shallowEqual(prevProps, nextProps) &&
current.ref === workInProgress.ref
) {
// ...
}
Copy the code
updateMemoComponent
// ...
letcompare = Component.compare; compare = compare ! = =null ? compare : shallowEqual;
if (compare(prevProps, nextProps) && current.ref === workInProgress.ref) {
return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);
}
// ...
Copy the code
As for why it is divided into two components, I don’t really understand, blue thin mushroom, probably related to update scheduling.
The Fiber node of SimpleMemoComponent is actually equal to the function component with a changed name, while MemoComponent is a shell, which needs to be peeled off to generate sub-fiber node, and then go to the function component based on the judgment of sub-fiber node.
The above is a comparison of Props