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

  1. First determine whether the two are the same object.
  2. Determine whether the two values are notobjectOr forNull.
  3. Comparing the twokeyThe length of the.
  4. To determine bothkeyWhether 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 incomingcompareFunction forSimpleMemoComponent.
  • Custom is passed incompareFunction 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