加入收藏 | 设为首页 | 会员中心 | 我要投稿 拼字网 - 核心网 (https://www.hexinwang.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 编程要点 > 语言 > 正文

PureComponent里是如何对比props?一文带你知道浅对比

发布时间:2022-11-17 11:06:14 所属栏目:语言 来源:
导读:   这篇文章给大家分享的是PureComponent里是如何对比props的内容,文中示例代码介绍的非常详细,对大家学习和理解浅对比有一定的帮助,感兴趣的朋友接下来一起跟随小编看看吧。
  
   类组件的Props对比
    这篇文章给大家分享的是PureComponent里是如何对比props的内容,文中示例代码介绍的非常详细,对大家学习和理解浅对比有一定的帮助,感兴趣的朋友接下来一起跟随小编看看吧。
  
      类组件的Props对比
      类组件是否需要更新需要实现shouldComponentUpdate方法,通常讲的是如果继承的是PureComponent则会有一个默认浅对比的实现。
  
  // 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;
      PureComponent的实现如上,我以前以为在声明时默认会实现shouldComponentUpdate方法,但实际上并没有一个默认的方法。
  
      接下来看看shouldComponentUpdate方法的调用。
  
  // ReactFiberClassComponent.js
  function checkShouldComponentUpdate(
    workInProgress,
    ctor,
    oldProps,
    newProps,
    oldState,
    newState,
    nextContext,
  ) {
    const instance = workInProgress.stateNode;
    // 如果实利实现了shouldComponentUpdate则返回调用它的结果
    if (typeof instance.shouldComponentUpdate === 'function') {
      const shouldUpdate = instance.shouldComponentUpdate(
        newProps,
        newState,
        nextContext,
      );
      return shouldUpdate;
    }
  
    // PureReactComponent的时候进行浅对比
    if (ctor.prototype && ctor.prototype.isPureReactComponent) {
      return (
        !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState)
      );
    }
  
    return true;
  }
      可以看出实际上并没有单独写一个shouldComponentUpdate方法给PureReactComponent,而是在对比的时候就返回浅对比的结果。
  
  浅对比的答案都在shallowEqual方法里了。
  
      shallowEqual 浅对比
  // shallowEqual.js
  function shallowEqual(objA: mixed, objB: mixed): boolean {
    // 一样的对象返回true
    if (Object.is(objA, objB)) {
      return true;
    }
  
    // 不是对象或者为null返回false
    if (
      typeof objA !== 'object' ||
      objA === null ||
      typeof objB !== 'object' ||
      objB === null
    ) {
      return false;
    }
  
    const keysA = Object.keys(objA);
    const keysB = Object.keys(objB);
  
    // key数量不同返回false
    if (keysA.length !== keysB.length) {
      return false;
    }
  
    // 对应key的值不相同返回false
    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;
  }
      shallowEqual方法原理很简单了
  
  先判断两者是否为同一对象。
  判断两者的值是否不为object或为null。
  对比两者key的长度。
  判断两者key对应的值是否相同。
      原来原理是这样简单的对比,如果我面试的时候能够口喷源码,会不会工资更高一些呢?
  
      函数组件的浅对比
      函数组件的浅对比方式则使用React.memo方法实现。
  
  // 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;
  }
      React.memo方法同样支持传入compare函数最为第二个参数。
  
      内部的处理其实是手动创建了一个$$typeof为REACT_MEMO_TYPE的ReactElement,方便之后的类型判断。
  
      React.memo组件的创建会稍微复杂一些,由于可以传入第二个自定义的compare函数,所以在内部其实会被定义为2种类型的Fiber节点。
  
  没有传入compare函数的为SimpleMemoComponent。
  传入了自定义compare函数的为MemoComponent。
      但是实际对于Props的比较都是相同的,默认都是调用shallowEqual方法来对比。
  
      updateSimpleMemoComponent
  
  if (
    shallowEqual(prevProps, nextProps) &&
    current.ref === workInProgress.ref
  ) {
  // ...
  }
      updateMemoComponent
  
  // ...
  let compare = Component.compare;
  compare = compare !== null ? compare : shallowEqual;
  if (compare(prevProps, nextProps) && current.ref === workInProgress.ref) {
    return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);
  }
  // ...
      至于为什么要分为2个组件,我也没大看懂,大概是和更新调度相关的。
  
      SimpleMemoComponent的Fiber节点实际等于改了个名的函数组件,走流程会直接走到函数组件里,而MemoComponent则是套了一层壳,需要先把壳剥开生成子Fiber节点,再由子Fiber节点的判断走到函数组件里。
 
 

(编辑:拼字网 - 核心网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!