美文网首页
PureComponent shallowEqual

PureComponent shallowEqual

作者: 别过经年 | 来源:发表于2018-11-07 12:19 被阅读79次

    react@16.6.1
    ReactFiberClassComponent

    function checkShouldComponentUpdate(
      workInProgress,
      ctor,
      oldProps,
      newProps,
      oldState,
      newState,
      nextContext,
    ) {
      const instance = workInProgress.stateNode;
      if (typeof instance.shouldComponentUpdate === 'function') {
        startPhaseTimer(workInProgress, 'shouldComponentUpdate');
        const shouldUpdate = instance.shouldComponentUpdate(
          newProps,
          newState,
          nextContext,
        );
        stopPhaseTimer();
    
        if (__DEV__) {
          warningWithoutStack(
            shouldUpdate !== undefined,
            '%s.shouldComponentUpdate(): Returned undefined instead of a ' +
              'boolean value. Make sure to return true or false.',
            getComponentName(ctor) || 'Component',
          );
        }
    
        return shouldUpdate;
      }
    
      if (ctor.prototype && ctor.prototype.isPureReactComponent) {
        return (
          !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState)
        );
      }
    
      return true;
    }
    

    ReactShallowRenderer.js

        let shouldUpdate = true;
        if (this._forcedUpdate) {
          shouldUpdate = true;
          this._forcedUpdate = false;
        } else if (typeof this._instance.shouldComponentUpdate === 'function') {
          shouldUpdate = !!this._instance.shouldComponentUpdate(
            props,
            state,
            context,
          );
        } else if (type.prototype && type.prototype.isPureReactComponent) {
          shouldUpdate =
            !shallowEqual(oldProps, props) || !shallowEqual(oldState, state);//在此做比对
        }
    

    shallowEqual.js

    const hasOwnProperty = Object.prototype.hasOwnProperty;
    
    /**
     * inlined Object.is polyfill to avoid requiring consumers ship their own
     * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
     */
    function is(x, y) {
      // SameValue algorithm
      if (x === y) {
        // Steps 1-5, 7-10
        // Steps 6.b-6.e: +0 != -0
        // Added the nonzero y check to make Flow happy, but it is redundant
        return x !== 0 || y !== 0 || 1 / x === 1 / y;
      } else {
        // Step 6.a: NaN == NaN
        return x !== x && y !== y;
      }
    }
    
    /**
     * Performs equality by iterating through keys on an object and returning false
     * when any key has values which are not strictly equal between the arguments.
     * Returns true when the values of all keys are strictly equal.
     */
    function shallowEqual(objA: mixed, objB: mixed): boolean {
      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;
    }
    
    export default shallowEqual;
    

    oldProps, newProps是所有属性的集合,就是个object,debug发现 好像每次两个对象的引用都是不同的,那么下面的这句话在比较oldProps, newProps总是返回false(猜测 有待证实)

      if (is(objA, objB)) {
        return true;
      }
    

    在代码里有这么一段

        return list.map(item => (
          <AppItem
            key={item.id}
            onDeleteItem={() => this.confirmDeleteItem(item.id)}
            copyItem={this.copyAppItem}
            data={item}
          />
        ));
    

    onDeleteItem的写法每次父组件数据更新,都是返回的新的函数,is(objA[keysA[i]], objB[keysA[i]])这句话永远不会成立,所以直接传递this.confirmDeleteItem进去,在AppItem内部传递id,这样PureComponent才会起作用

    react源码

    模拟props,对shallowEqual进行测试

    
    const data = {
      list: [
        {
          name: "aaa",
          sex: "man"
        },
        {
          name: "bbb",
          sex: "woman"
        }
      ],
      status: true
    };
    
    const newData = { ...data };
    //如果不解构再赋值因为引用是相同的,如果我改变newData.list[0].name = "geek",
    //shallowEqual对比出来返回两者是true,不会重新render。
    //但是如果解构,如果我没有改变任何数据shallowEqual返回的都是false,都会重新render
    //但是在redux里面 如果我想改变数据才会发dispatch,
    //自然需要更新数据(这里面可能会存在数据没改变不需要re-render的情况)
    
    newData.list[0].name = "geek"; //newData和data的list是同一个引用
    
    const props = { data };
    const newProps = { data: newData };
    
    console.info(props, newProps);
    
    console.log(shallowEqual(props, newProps)); //false 走render
    

    相关文章

      网友评论

          本文标题:PureComponent shallowEqual

          本文链接:https://www.haomeiwen.com/subject/ehamxqtx.html