ReactNote05:深入源码探究memo、PureComponent

深入源码探究memo、PureComponent

窥探PureComponent

今天学到了PureComponent,它可以起到在Component里面添加SCU的效果,虽然类组件以后会很少用,但是它的底层原理还是要了解一下,也能了解一下React不断进步背后的思想,PureComponent在React里面是怎么实现的呢,肘,跟我进源码(版本是16.3.1)。

这里安利一下vscode的Bookmarks插件,看源码是非常方便。

以下源码均为节选

// 路径
// packages/react-reconciler/src/ReactFiberClassComponent.js

function checkShouldComponentUpdate(
  workInProgress,
  ctor,
  oldProps,
  newProps,
  oldState,
  newState,
  nextContext,
) {
  const instance = workInProgress.stateNode;
    
  // 判断是否使用了shouldComponentUpdate
  if (typeof instance.shouldComponentUpdate === 'function') {
    // 使用了shouldComponentUpdate的话,那么就比较State和props的数据
    // 如果变化就返回true,不变化的话就返回false
    const shouldUpdate = instance.shouldComponentUpdate(
      newProps,
      newState,
      nextContext,
    );
    return shouldUpdate;
  }

  // 判断是否使用了PureReactComponent
  if (ctor.prototype && ctor.prototype.isPureReactComponent) {
    return (
      // 浅层比较,注意有取反操作
      !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState)
    );
  }
    
  // 默认返回的是true,也就是更新
  return true;
}

这里就弄清楚了判断组件的更新的逻辑,下面我们再看一下shallowEqual这个函数,按住commond进去,

import shallowEqual from 'shared/shallowEqual';

share文件夹里面找shallowEqual这个文件

function shallowEqual(objA: mixed, objB: mixed): boolean {
  // 同一个对象返回ture,到了checkShouldComponentUpdate那里就是false,因为进行取反操作了
  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);
	
  // 如果两个对象的key的长度不一样的话,那么数据肯定发生了变化
  if (keysA.length !== keysB.length) {
    return false;
  }
	
  // 如果A中和B中的key值不一样,那就更新
  // 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;
}

窥探memo

既然memo和PureComponent作用类似,那么其原理应该也是和PureComponent思想类似

// packages/react/src/memo.js
import {REACT_MEMO_TYPE} from 'shared/ReactSymbols';
import isValidElementType from 'shared/isValidElementType';

// 这里是可以传入两个参数的,如果没有传入第二个参数呢?
export default function memo<Props>(
  type: React$ElementType,
  compare?: (oldProps: Props, newProps: Props) => boolean,
) {
  return {
    $$typeof: REACT_MEMO_TYPE,
    type,
    compare: compare === undefined ? null : compare,
  };
}

那么源码已经用compare = compare !== null ? compare : shallowEqual;帮助我们做了判断,意思就是如果我们传入了自己编写的compare函数,那么就用这个函数,否则它帮我们调用shallowEqual函数。

function updateMemoComponent(
  current: Fiber | null,
  workInProgress: Fiber,
  Component: any,
  nextProps: any,
  updateExpirationTime,
  renderExpirationTime: ExpirationTime,
): null | Fiber {
  
  let currentChild = ((current.child: any): Fiber); // This is always exactly one child
  if (updateExpirationTime < renderExpirationTime) {
    const prevProps = currentChild.memoizedProps;
    let compare = Component.compare;
    compare = compare !== null ? compare : shallowEqual;
    if (compare(prevProps, nextProps) && current.ref === workInProgress.ref) {
      return bailoutOnAlreadyFinishedWork(
        current,
        workInProgress,
        renderExpirationTime,
      );
    }
  }
}
------------- 本文结束 感谢阅读 -------------