react中對PureComponent的深度認識

談react優化其中最重要的一個組件就是PureComponent,主要的特點就是當數據即使發生深層次的變化,PureComponent也不會更新而且影響到子組件。
那PureComponent和Component的之間的聯繫在哪裏,以下是對react框架代碼的一些理解。

一、都是從React.js中暴露出來, 刪除多此次不相關代碼

import {Component, PureComponent} from './ReactBaseClasses';


const React = {
  Children: {
    map,
    forEach,
    count,
    toArray,
    only,
  },

  createRef,
  Component,
  PureComponent,

 
};


export default React;

此處可以看到Component都是來自於ReactBaseClasses.js,這樣就很有意思了。PureComponent其實就是繼承自Component, 注意ComponentDummy個人理解爲Component複製品

function Component(props, context, updater) {
  this.props = props;
  this.context = context;
  this.refs = emptyObject;
  this.updater = updater || ReactNoopUpdateQueue;
}

Component.prototype.isReactComponent = {};
//  這裏就是很熟悉的setSate
Component.prototype.setState = function(partialState, callback) {
  invariant(
    typeof partialState === 'object' ||
      typeof partialState === 'function' ||
      partialState == null,
    'setState(...): takes an object of state variables to update or a ' +
      'function which returns an object of state variables.',
  );
  //  爲什麼說 setState異步的,updater更新的是一個隊列
  this.updater.enqueueSetState(this, partialState, callback, 'setState');
};

// 強制更新 
Component.prototype.forceUpdate = function(callback) {
  this.updater.enqueueForceUpdate(this, callback, 'forceUpdate');
};
// 聲明一個複製品Component,利用其原型繼承Component的原型
function ComponentDummy() {}
ComponentDummy.prototype = Component.prototype;

// 申明PureComponent
function PureComponent(props, context, updater) {
  this.props = props;
  this.context = context;
 
  this.refs = emptyObject;
  this.updater = updater || ReactNoopUpdateQueue;
}
// PureComponent原型再繼承,複製品Component
const pureComponentPrototype = (PureComponent.prototype = new ComponentDummy());
pureComponentPrototype.constructor = PureComponent;
// assign 淺複製 Component的原型到 PureComponent
Object.assign(pureComponentPrototype, Component.prototype);
// 這裏就是 PureComponent 和 Component 的區別加入了一個 isPureReactComponent  = true
pureComponentPrototype.isPureReactComponent = true;

export {Component, PureComponent};

二、淺比較是怎麼發生的
1、我們還是回到React.js 文件中React 包含方法

import {
  createElement,
  createFactory,
  cloneElement,
  isValidElement,
} from './ReactElement';
const React = {
  createElement: __DEV__ ? createElementWithValidation : createElement,
  cloneElement: __DEV__ ? cloneElementWithValidation : cloneElement,
  createFactory: __DEV__ ? createFactoryWithValidation : createFactory,
 }

2、在ReactElemene.js中通過createElement創建Element

import ReactCurrentOwner from './ReactCurrentOwner';

const ReactElement = function(type, key, ref, self, source, owner, props) {
  const element = {

    $$typeof: REACT_ELEMENT_TYPE,

    type: type,
    key: key,
    ref: ref,
    props: props,


    _owner: owner,
  };
  return element;
};

export function createElement(type, config, children) {
  let propName;

  const props = {};

  let key = null;
  let ref = null;
  let self = null;
  let source = null;

  if (config != null) {
    if (hasValidRef(config)) {
      ref = config.ref;
    }
    if (hasValidKey(config)) {
      key = '' + config.key;
    }

    self = config.__self === undefined ? null : config.__self;
    source = config.__source === undefined ? null : config.__source;
    // Remaining properties are added to a new props object
    for (propName in config) {
      if (
        hasOwnProperty.call(config, propName) &&
        !RESERVED_PROPS.hasOwnProperty(propName)
      ) {
        props[propName] = config[propName];
      }
    }
  }

  const childrenLength = arguments.length - 2;
  if (childrenLength === 1) {
    props.children = children;
  } else if (childrenLength > 1) {
    const childArray = Array(childrenLength);
    for (let i = 0; i < childrenLength; i++) {
      childArray[i] = arguments[i + 2];
    }
    props.children = childArray;
  }

  // Resolve default props
  if (type && type.defaultProps) {
    const defaultProps = type.defaultProps;
    for (propName in defaultProps) {
      if (props[propName] === undefined) {
        props[propName] = defaultProps[propName];
      }
    }
  }
  // 每一個新創建的element都同時返回ReactCurrentOwner,用於跟蹤當前element
  return ReactElement(
    type,
    key,
    ref,
    self,
    source,
    ReactCurrentOwner.current,
    props,
  );
}

3、看到這裏就明白了,創建的元素關聯上Owner其實就是一個Fiber對象,在整個Fiber模塊裏就能發現其中的比較

import type {Fiber} from 'react-reconciler/src/ReactFiber';

const ReactCurrentOwner = {
  /**
   * @internal
   * @type {ReactComponent}
   */
  current: (null: null | Fiber),
};

export default ReactCurrentOwner;

4、ReactFiberClassComponent是否爲PureComponent,其中ctor其實就是Component

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();

   
    return shouldUpdate;
  }

  if (ctor.prototype && ctor.prototype.isPureReactComponent) {
    return (
      !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState)
    );
  }

  return true;
}

四、在Fiber最終執行後體現的是在ReactDOM中。和react-reconciler關聯起來在ReactFiberBeginWork模塊中調用ReactFiberClassComponent的方法

function beginWork(
  current: Fiber | null,
  workInProgress: Fiber,
  renderExpirationTime: ExpirationTime,
): Fiber | null {
  const updateExpirationTime = workInProgress.expirationTime;

  // Before entering the begin phase, clear the expiration time.
  workInProgress.expirationTime = NoWork;

  switch (workInProgress.tag) {
	// 不確定組件,其實就是剛開始創建的組件還未指定類型
	case IndeterminateComponent: {
    }
    // 懶加載組件
    case LazyComponent: {
    }
    // 函數式組件
    case FunctionComponent: {
    }
    // class組件具有什麼週期
    case ClassComponent: {
      const Component = workInProgress.type;
      const unresolvedProps = workInProgress.pendingProps;
      const resolvedProps =
        workInProgress.elementType === Component
          ? unresolvedProps
          : resolveDefaultProps(Component, unresolvedProps);
      return updateClassComponent(
        current,
        workInProgress,
        Component,
        resolvedProps,
        renderExpirationTime,
      );
    }

  }

}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章