ReactCompositeComponent源码(待定)

ReactCompositeComponent模块用于实例化组件、及完成组件元素的挂载、重绘组件等。

 

'use strict';

var _prodInvariant = require('./reactProdInvariant'),// 生产环境React形式带url报错 
    _assign = require('object-assign');

var React = require('react/lib/React');

// 提供ReactComponentEnvironment.replaceNodeWithMarkup方法,用于替换挂载的Dom元素
var ReactComponentEnvironment = require('./ReactComponentEnvironment');

// 开发环境下,ReactClass组件被实例化或其render方法被调用时,向ReactCurrentOwner.current添加当前实例this
// 实例化完成或render方法执行完成,ReactCurrentOwner.current置为null
var ReactCurrentOwner = require('react/lib/ReactCurrentOwner');

// 调试用
var ReactErrorUtils = require('./ReactErrorUtils');

// 以对象形式存储组件实例
var ReactInstanceMap = require('./ReactInstanceMap');

// 调试用
var ReactInstrumentation = require('./ReactInstrumentation');

// 用于判断节点类型,ReactComponentElement元素返回1;ReactDomElement元素返回0;若为空,返回2
var ReactNodeTypes = require('./ReactNodeTypes');

// 用于挂载、移除、更新组件实例,作为方法的发起者,如ReactReconciler.mountComponent
var ReactReconciler = require('./ReactReconciler');

if (process.env.NODE_ENV !== 'production') {
  var checkReactTypeSpec = require('./checkReactTypeSpec');
}

// 空对象,并且用Object.freeze冻结为不可修改、不可扩展
var emptyObject = require('fbjs/lib/emptyObject');

// invariant(condition,format,a,b,c,d,e,f) condition为否值,替换format中的"%s",并throw error报错  
var invariant = require('fbjs/lib/invariant');

// shallowEqual(A,B)比较值相等,及浅比较键值相等
var shallowEqual = require('fbjs/lib/shallowEqual');

// 判断组件重绘时是采用更新组件实例的方式(返回真值);还是采用销毁实例后、重新创建实例的方式(返回否值)
// 组件元素的构造函数或key值不同,销毁实例后再行创建
var shouldUpdateReactComponent = require('./shouldUpdateReactComponent');

// warning(condition,format) condition为否值,替换format中的"%s",并console.error警告 
var warning = require('fbjs/lib/warning');

// 区分纯函数无状态组件、PureComponent纯组件、Component组件的标识符
var CompositeTypes = {
  ImpureClass: 0,// 组件,继承自React.Component
  PureClass: 1,// 纯组件,继承自React.PureComponent,不能设置shouldComponentUpdate方法,重绘时判断props、state是否变更
  StatelessFunctional: 2// 纯函数无状态组件,function(props,context,updateQueue){}形式
};

// 将无状态组件function(props,context,updateQueue){}包装为带有render原型方法的构造函数形式
function StatelessComponent(Component) {}
StatelessComponent.prototype.render = function () {
  var Component = ReactInstanceMap.get(this)._currentElement.type;
  var element = Component(this.props, this.context, this.updater);
  warnIfInvalidElement(Component, element);
  return element;
};

// 校验无状态组件返回值必须是ReactElement,以及不能设置childContextTypes静态属性
function warnIfInvalidElement(Component, element) {
  if (process.env.NODE_ENV !== 'production') {
    process.env.NODE_ENV !== 'production' ? 
      warning(element === null || element === false || React.isValidElement(element), 
        '%s(...): A valid React element (or null) must be returned. You may have ' 
        + 'returned undefined, an array or some other invalid object.', 
        Component.displayName || Component.name || 'Component') 
      : void 0;
    process.env.NODE_ENV !== 'production' ? 
      warning(!Component.childContextTypes, 
        '%s(...): childContextTypes cannot be defined on a functional component.', 
        Component.displayName || Component.name || 'Component') 
      : void 0;
  }
}

// 校验是否纯组件或组件;返回否值,当作非状态组件、或ReactClass的工厂函数处理
function shouldConstruct(Component) {
  return !!(Component.prototype && Component.prototype.isReactComponent);
}

function isPureComponent(Component) {
  return !!(Component.prototype && Component.prototype.isPureReactComponent);
}

// 开发环境下带调试方式执行fn
function measureLifeCyclePerf(fn, debugID, timerType) {
  if (debugID === 0) {
    // Top-level wrappers (see ReactMount) and empty components (see
    // ReactDOMEmptyComponent) are invisible to hooks and devtools.
    // Both are implementation details that should go away in the future.
    return fn();
  }

  ReactInstrumentation.debugTool.onBeginLifeCycleTimer(debugID, timerType);
  try {
    return fn();
  } finally {
    ReactInstrumentation.debugTool.onEndLifeCycleTimer(debugID, timerType);
  }
}

var nextMountID = 1;

// 自定义组件实例化、挂载、移除、更新实现
var ReactCompositeComponent = {
  // 实例化
  construct: function (element) {
    this._currentElement = element;// ReactComponentElement,配置了组件的构造函数、props属性等
    this._rootNodeID = 0;
    this._compositeType = null;// 区分纯函数无状态组件、继承自PureComponent的纯组件、以及继承自Component的组件
    this._instance = null;// ReactComponent实例
    this._hostParent = null;// 文档元素,作为组件元素的父节点
    this._hostContainerInfo = null;

    // See ReactUpdateQueue
    this._updateBatchNumber = null;
    this._pendingElement = null;// ReactDom.render方法渲染时包裹元素由react组件渲染,_pendingElement存储待渲染元素
    this._pendingStateQueue = null;// 组件调用setState、replaceState方法,通过ReactUpdateQueue将更迭后的state推入_pendingStateQueue
    this._pendingReplaceState = false;// 判断组件是否通过调用replaceState方法向_pendingStateQueue推入state数据
    this._pendingForceUpdate = false;// 组件调用forceUpdate赋值为真

    this._renderedNodeType = null;// 节点类型,区分ReactComponentElement、ReactDomElement元素
    this._renderedComponent = null;// render方法内子组件实例
    this._context = null;// 赋值给组件的context属性
    this._mountOrder = 0;// 挂载的第几个组件
    this._topLevelWrapper = null;

    // See ReactUpdates and ReactUpdateQueue.
    this._pendingCallbacks = null;

    // ComponentWillUnmount shall only be called once
    this._calledComponentWillUnmount = false;

    if (process.env.NODE_ENV !== 'production') {
      this._warnedAboutRefsInRender = false;
    }
  },

  // 由ReactReconciler.mountComponent方法发起

  // 关于参数:
  // 参数transaction默认为ReactUpdates.ReactReconcileTransaction,即ReactReconcileTransaction模块
  //    用于在组件元素挂载前后执行指定的钩子函数,选中文本回撤、阻止事件触发、生命周期钩子和调试等
  //    特别是通过执行getReactMountReady().enqueue()方法,添加componentDidMount、componentDidUpdate生命周期钩子
  //    其次是通过执行getUpdateQueue()方法,向组件实例注入updater参数,默认是ReactUpdateQueue模块
  //    意义是为组件的setState、replaceState、forceUpdate方法完成功能提供必要的函数
  // 参数context或者为空对象,或者由上层组件提供,后者混合this.context和this.getChildContext()形成

  // 完成组件实例化,执行实例的render方法,通过ReactDomComponent绘制DomLazyTree,挂载componentDidMount函数
  mountComponent: function (transaction, hostParent, hostContainerInfo, context) {
    var _this = this;

    this._context = context;
    this._mountOrder = nextMountID++;
    this._hostParent = hostParent;
    this._hostContainerInfo = hostContainerInfo;

    // 添加到ReactComponentElement元素的props属性
    var publicProps = this._currentElement.props;

    // 通过Component.contextTypes过滤由上层组件注入的context属性,并做校验
    var publicContext = this._processContext(context);

    // 纯函数无状态组件、或者继承自PureComponent的纯组件构造函数、或者继承自Component的组件构造函数
    var Component = this._currentElement.type;

    // 传入组件ReactComponent的第三个参数updater,默认是ReactUpdateQueue模块,用于实现setState等方法
    var updateQueue = transaction.getUpdateQueue();

    // 校验是否纯组件或组件;返回否值,当作非状态组件、或ReactClass的工厂函数处理
    var doConstruct = shouldConstruct(Component);

    // 创建纯组件或组件实例,或者获取无状态组件的返回值
    var inst = this._constructComponent(doConstruct, publicProps, publicContext, updateQueue);

    // 待挂载的ReactComponentElement元素
    var renderedElement;

    // Component为纯函数无状态组件书写方式
    if (!doConstruct && (inst == null || inst.render == null)) {
      // 无状态组件返回值即是待挂载的ReactElement
      renderedElement = inst;

      // 校验无状态组件返回值必须是ReactElement,以及不能设置childContextTypes静态属性
      warnIfInvalidElement(Component, renderedElement);

      // 校验无状态组件的返回值是否ReactElement
      !(inst === null || inst === false || React.isValidElement(inst)) ? 
        process.env.NODE_ENV !== 'production' ? 
          invariant(false, '%s(...): A valid React element (or null) must be returned. ' 
            + 'You may have returned undefined, an array or some other invalid object.', 
            Component.displayName || Component.name || 'Component') 
          : _prodInvariant('105', Component.displayName || Component.name || 'Component') 
          : void 0;
      
      // 将无状态组件function(props,context,updateQueue){}包装为带有render原型方法的构造函数形式
      inst = new StatelessComponent(Component);

      // 添加无状态组件标识
      this._compositeType = CompositeTypes.StatelessFunctional;

    // Component为纯组件或组件形式
    } else {
      if (isPureComponent(Component)) {
        // 添加纯组件标识
        this._compositeType = CompositeTypes.PureClass;
      } else {
        // 添加组件标识
        this._compositeType = CompositeTypes.ImpureClass;
      }
    }

    // 实例没有render方法,或者props属性同publicProps不符,警告
    if (process.env.NODE_ENV !== 'production') {
      if (inst.render == null) {
        process.env.NODE_ENV !== 'production' ? 
          warning(false, '%s(...): No `render` method found on the returned component ' 
            + 'instance: you may have forgotten to define `render`.', 
            Component.displayName || Component.name || 'Component') 
          : void 0;
      }

      var propsMutated = inst.props !== publicProps;
      var componentName = Component.displayName || Component.name || 'Component';

      process.env.NODE_ENV !== 'production' ? 
        warning(inst.props === undefined || !propsMutated, 
          '%s(...): When calling super() in `%s`, make sure to pass ' 
          + 'up the same props that your component\'s constructor was passed.', 
          componentName, componentName) 
        : void 0;
    }

    // 原本作为构造函数的参数传入,为方便起见,再次赋值,同时保证实例数据的准确性
    inst.props = publicProps;
    inst.context = publicContext;
    inst.refs = emptyObject;
    inst.updater = updateQueue;

    this._instance = inst;

    // ReactInstanceMap中添加组件实例
    ReactInstanceMap.set(inst, this);

    if (process.env.NODE_ENV !== 'production') {
      // 组件不是由ReactClass方式创建,且添加了getInitialState或getDefaultProps方法,警告
      process.env.NODE_ENV !== 'production' ? 
        warning(!inst.getInitialState || inst.getInitialState.isReactClassApproved || inst.state, 
          'getInitialState was defined on %s, a plain JavaScript class. ' 
          + 'This is only supported for classes created using React.createClass. ' 
          + 'Did you mean to define a state property instead?', 
          this.getName() || 'a component') 
        : void 0;
      process.env.NODE_ENV !== 'production' ? 
        warning(!inst.getDefaultProps || inst.getDefaultProps.isReactClassApproved, 
          'getDefaultProps was defined on %s, a plain JavaScript class. ' 
          + 'This is only supported for classes created using React.createClass. ' 
          + 'Use a static property to define defaultProps instead.', 
          this.getName() || 'a component') 
        : void 0;

      // 静态属性propTypes、contextTypes书写为原型属性提示,只构造函数拥有,实例没有
      process.env.NODE_ENV !== 'production' ? 
        warning(!inst.propTypes, 
          'propTypes was defined as an instance property on %s. Use a static ' 
          + 'property to define propTypes instead.', this.getName() || 'a component') 
        : void 0;
      process.env.NODE_ENV !== 'production' ? 
        warning(!inst.contextTypes, 
          'contextTypes was defined as an instance property on %s. Use a ' 
          + 'static property to define contextTypes instead.', this.getName() || 'a component') 
        : void 0;

      // 接口变动更改
      process.env.NODE_ENV !== 'production' ? 
        warning(typeof inst.componentShouldUpdate !== 'function', '%s has a method called ' 
          + 'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' 
          + 'The name is phrased as a question because the function is ' 
          + 'expected to return a value.', this.getName() || 'A component') 
        : void 0;
      process.env.NODE_ENV !== 'production' ? 
        warning(typeof inst.componentDidUnmount !== 'function', '%s has a method called ' 
          + 'componentDidUnmount(). But there is no such lifecycle method. ' 
          + 'Did you mean componentWillUnmount()?', this.getName() || 'A component') 
        : void 0;
      process.env.NODE_ENV !== 'production' ? 
        warning(typeof inst.componentWillRecieveProps !== 'function', '%s has a method called ' 
          + 'componentWillRecieveProps(). Did you mean componentWillReceiveProps()?', 
          this.getName() || 'A component') 
        : void 0;
    }

    // 获取初始state,并提示state只能设置为对象形式
    var initialState = inst.state;
    if (initialState === undefined) {
      inst.state = initialState = null;
    }
    !(typeof initialState === 'object' && !Array.isArray(initialState)) ? 
      process.env.NODE_ENV !== 'production' ? 
        invariant(false, '%s.state: must be set to an object or null', 
          this.getName() || 'ReactCompositeComponent') 
        : _prodInvariant('106', this.getName() || 'ReactCompositeComponent') 
      : void 0;

    this._pendingStateQueue = null;
    this._pendingReplaceState = false;
    this._pendingForceUpdate = false;

    // 执行实例inst的render方法,嵌套调用mountComponent,将返回值ReactNode元素转化成DomLazyTree输出
    var markup;
    if (inst.unstable_handleError) {
      markup = this.performInitialMountWithErrorHandling(renderedElement, hostParent, hostContainerInfo, transaction, context);
    } else {
      markup = this.performInitialMount(renderedElement, hostParent, hostContainerInfo, transaction, context);
    }

    // 向后置钩子transaction.getReactMountReady()中添加实例的生命周期方法componentDidMount
    if (inst.componentDidMount) {
      if (process.env.NODE_ENV !== 'production') {
        transaction.getReactMountReady().enqueue(function () {
          measureLifeCyclePerf(function () {
            return inst.componentDidMount();
          }, _this._debugID, 'componentDidMount');
        });
      } else {
        transaction.getReactMountReady().enqueue(inst.componentDidMount, inst);
      }
    }

    return markup;
  },

  // 创建纯组件或组件实例,或者获取无状态组件的返回值
  _constructComponent: function (doConstruct, publicProps, publicContext, updateQueue) {
    if (process.env.NODE_ENV !== 'production') {
      ReactCurrentOwner.current = this;
      try {
        // 创建纯组件或组件实例,或者获取无状态组件的返回值
        return this._constructComponentWithoutOwner(doConstruct, publicProps, publicContext, updateQueue);
      } finally {
        ReactCurrentOwner.current = null;
      }
    } else {
      return this._constructComponentWithoutOwner(doConstruct, publicProps, publicContext, updateQueue);
    }
  },

  // 创建纯组件或组件实例,或者获取无状态组件的返回值
  _constructComponentWithoutOwner: function (doConstruct, publicProps, publicContext, updateQueue) {
    var Component = this._currentElement.type;

    // Component为纯组件或组件,创建实例;Component可能为TopLevelWrapper
    if (doConstruct) {
      if (process.env.NODE_ENV !== 'production') {
        return measureLifeCyclePerf(function () {
          return new Component(publicProps, publicContext, updateQueue);
        }, this._debugID, 'ctor');
      } else {
        return new Component(publicProps, publicContext, updateQueue);
      }
    }

    // Component为工厂函数ReactClassFacory=function(props,context,updateQueue){
    //     return new ReactClass(props,context,updateQueue)   
    // }
    // 或者,无状态组件纯函数形式function(props,context,updateQueue){}
    if (process.env.NODE_ENV !== 'production') {
      return measureLifeCyclePerf(function () {
        return Component(publicProps, publicContext, updateQueue);
      }, this._debugID, 'render');
    } else {
      return Component(publicProps, publicContext, updateQueue);
    }
  },

  performInitialMountWithErrorHandling: function (renderedElement, hostParent, hostContainerInfo, transaction, context) {
    var markup;
    var checkpoint = transaction.checkpoint();
    try {
      markup = this.performInitialMount(renderedElement, hostParent, hostContainerInfo, transaction, context);
    } catch (e) {
      // Roll back to checkpoint, handle error (which may add items to the transaction), and take a new checkpoint
      transaction.rollback(checkpoint);
      this._instance.unstable_handleError(e);
      if (this._pendingStateQueue) {
        // _processPendingState方法获取组件setState、replaceState方法执行后的最终state
        this._instance.state = this._processPendingState(this._instance.props, this._instance.context);
      }
      checkpoint = transaction.checkpoint();

      this._renderedComponent.unmountComponent(true);
      transaction.rollback(checkpoint);

      // Try again - we've informed the component about the error, so they can render an error message this time.
      // If this throws again, the error will bubble up (and can be caught by a higher error boundary).
      markup = this.performInitialMount(renderedElement, hostParent, hostContainerInfo, transaction, context);
    }
    return markup;
  },

  // 执行ReactComponent实例的render方法,获取其返回值ReactNode
  // 嵌套调用mountComponent,完成ReactNode元素相应组件的实例化和render方法执行
  // 最终通过ReactDomElement转化为DOMLazyTree对象输出,其node属性为需要插入文档dom对象
  performInitialMount: function (renderedElement, hostParent, hostContainerInfo, transaction, context) {
    var inst = this._instance;

    var debugID = 0;
    if (process.env.NODE_ENV !== 'production') {
      debugID = this._debugID;
    }

    // 执行组件实例的componentWillMount方法
    // componentWillMount方法内调用setState、replaceState,_pendingStateQueue有值,刷新state后再行绘制
    if (inst.componentWillMount) {
      if (process.env.NODE_ENV !== 'production') {
        measureLifeCyclePerf(function () {
          return inst.componentWillMount();
        }, debugID, 'componentWillMount');
      } else {
        inst.componentWillMount();
      }

      if (this._pendingStateQueue) {
        // _processPendingState方法获取组件setState、replaceState方法执行后的最终state
        inst.state = this._processPendingState(inst.props, inst.context);
      }
    }

    // 间接执行ReactClass或TopLevelWrapper实例的render方法,获取待挂载的元素ReactNode
    // 组件若为函数式无状态组件function(props,context,updateQueue){},renderedElement由传参提供
    if (renderedElement === undefined) {
      // 调用组件实例inst的render方法,获取待挂载的元素ReactNode
      renderedElement = this._renderValidatedComponent();
    }

    // 节点类型,ReactComponentElement元素返回1;ReactDomElement元素返回0;若为空,返回2
    var nodeType = ReactNodeTypes.getType(renderedElement);
    this._renderedNodeType = nodeType;

    // 调用instantiateReactComponent模块以实例化render方法的返回值,即renderedElement元素
    var child = this._instantiateReactComponent(renderedElement, nodeType !== ReactNodeTypes.EMPTY /* shouldHaveDebugID */
    );

    // render方法内子组件实例
    this._renderedComponent = child;

    // 嵌套调用mountComponent,完成renderedElement元素相应组件的实例化及render方法执行
    // 最终通过ReactDomElement转化为DOMLazyTree对象输出,其node属性为需要插入文档dom对象
    var markup = ReactReconciler.mountComponent(child, transaction, hostParent, hostContainerInfo, this._processChildContext(context), debugID);

    if (process.env.NODE_ENV !== 'production') {
      if (debugID !== 0) {
        var childDebugIDs = child._debugID !== 0 ? [child._debugID] : [];
        ReactInstrumentation.debugTool.onSetChildren(debugID, childDebugIDs);
      }
    }

    return markup;
  },

  // 由render方法内子组件实例,通过ReactDomComponent等,获取相应的dom节点
  getHostNode: function () {
    return ReactReconciler.getHostNode(this._renderedComponent);
  },

  // 移除组件,执行componentWillUnmount方法
  unmountComponent: function (safely) {
    if (!this._renderedComponent) {
      return;
    }

    var inst = this._instance;

    if (inst.componentWillUnmount && !inst._calledComponentWillUnmount) {
      inst._calledComponentWillUnmount = true;

      if (safely) {
        var name = this.getName() + '.componentWillUnmount()';
        ReactErrorUtils.invokeGuardedCallback(name, inst.componentWillUnmount.bind(inst));
      } else {
        if (process.env.NODE_ENV !== 'production') {
          measureLifeCyclePerf(function () {
            return inst.componentWillUnmount();
          }, this._debugID, 'componentWillUnmount');
        } else {
          inst.componentWillUnmount();
        }
      }
    }

    if (this._renderedComponent) {
      ReactReconciler.unmountComponent(this._renderedComponent, safely);
      this._renderedNodeType = null;
      this._renderedComponent = null;
      this._instance = null;
    }

    this._pendingStateQueue = null;
    this._pendingReplaceState = false;
    this._pendingForceUpdate = false;
    this._pendingCallbacks = null;
    this._pendingElement = null;

    this._context = null;
    this._rootNodeID = 0;
    this._topLevelWrapper = null;

    ReactInstanceMap.remove(inst);
  },

  // 通过Component.contextTypes过滤由上层组件注入的context属性,仅保留Component.contextTypes约定的
  _maskContext: function (context) {
    var Component = this._currentElement.type;
    var contextTypes = Component.contextTypes;
    if (!contextTypes) {
      return emptyObject;
    }
    var maskedContext = {};
    for (var contextName in contextTypes) {
      maskedContext[contextName] = context[contextName];
    }
    return maskedContext;
  },

  // 通过Component.contextTypes过滤由上层组件注入的context属性,并做校验
  _processContext: function (context) {
    var maskedContext = this._maskContext(context);
    if (process.env.NODE_ENV !== 'production') {
      var Component = this._currentElement.type;
      if (Component.contextTypes) {
        this._checkContextTypes(Component.contextTypes, maskedContext, 'context');
      }
    }
    return maskedContext;
  },

  // 将当前组件的Context注入子组件;执行getChildContext方法并作校验,注入子组件的context中
  _processChildContext: function (currentContext) {
    var Component = this._currentElement.type;
    var inst = this._instance;
    var childContext;

    if (inst.getChildContext) {
      if (process.env.NODE_ENV !== 'production') {
        ReactInstrumentation.debugTool.onBeginProcessingChildContext();
        try {
          childContext = inst.getChildContext();
        } finally {
          ReactInstrumentation.debugTool.onEndProcessingChildContext();
        }
      } else {
        childContext = inst.getChildContext();
      }
    }

    if (childContext) {
      !(typeof Component.childContextTypes === 'object') ? 
        process.env.NODE_ENV !== 'production' ? 
          invariant(false, '%s.getChildContext(): ' 
            + 'childContextTypes must be defined in order to use getChildContext().', 
            this.getName() || 'ReactCompositeComponent') 
          : _prodInvariant('107', this.getName() || 'ReactCompositeComponent') 
        : void 0;

      if (process.env.NODE_ENV !== 'production') {
        this._checkContextTypes(Component.childContextTypes, childContext, 'childContext');
      }
      for (var name in childContext) {
        !(name in Component.childContextTypes) ? 
          process.env.NODE_ENV !== 'production' ? 
            invariant(false, '%s.getChildContext(): key "%s" is not defined in childContextTypes.', 
              this.getName() || 'ReactCompositeComponent', name) 
            : _prodInvariant('108', this.getName() || 'ReactCompositeComponent', name) 
          : void 0;
      }
      return _assign({}, currentContext, childContext);
    }
    return currentContext;
  },

  // 校验context
  _checkContextTypes: function (typeSpecs, values, location) {
    if (process.env.NODE_ENV !== 'production') {
      checkReactTypeSpec(typeSpecs, values, location, this.getName(), null, this._debugID);
    }
  },

  // 接受新的组件待渲染元素nextElement,以替换旧的组件元素this._currentElement
  // 通过performUpdateIfNecessary方法调用,nextElement由this._pendingElement提供
  //    该方法触发执行的实际情形是ReactDom.render(ReactNode,pNode)挂载的组件元素,其父节点pNode由react方式绘制
  // 通过_updateRenderedComponent方法调用,nextElement为待变更的子组件元素
  receiveComponent: function (nextElement, transaction, nextContext) {
    var prevElement = this._currentElement;
    var prevContext = this._context;

    this._pendingElement = null;

    this.updateComponent(transaction, prevElement, nextElement, prevContext, nextContext);
  },

  // 由ReactDom.render(ReactNode,pNode)方法插入文档时,pNode由react方式绘制
  //    调用ReactReconciler.receiveComponent间接执行updateComponent方法重绘组件
  // 组件的setState、replaceState、forceUpdate方法触发重绘,直接调用updateComponent方法重绘组件
  performUpdateIfNecessary: function (transaction) {
    // ReactDom.render方法渲染时包裹元素由react组件渲染,将待渲染元素推入_pendingElement中
    if (this._pendingElement != null) {
      ReactReconciler.receiveComponent(this, this._pendingElement, transaction, this._context);

    // 通过调用组件的setState、replaceState、forceUpdate方法重绘组件
    } else if (this._pendingStateQueue !== null || this._pendingForceUpdate) {
      this.updateComponent(transaction, this._currentElement, this._currentElement, this._context, this._context);
    
    } else {
      this._updateBatchNumber = null;
    }
  },

  // 判断props变更情况,执行shouldComponentUpdate方法,重绘组件或者更改组件的属性
  // 参数transaction,组件重绘时用于向子组件提供updater参数,setState等方法可用;以及实现componentWillMount挂载功能
  // 参数prevParentElement变更前的组件元素ReactNode,nextParentElement变更后的组件元素,作为render方法渲染节点的父元素
  // 参数prevUnmaskedContext更迭前的context,nextUnmaskedContext更迭后的context
  updateComponent: function (transaction, prevParentElement, nextParentElement, prevUnmaskedContext, nextUnmaskedContext) {
    var inst = this._instance;

    // 组件实例尚未生成,报错
    !(inst != null) ? process.env.NODE_ENV !== 'production' ? 
      invariant(false, 
        'Attempted to update component `%s` that has already been unmounted (or failed to mount).', 
        this.getName() || 'ReactCompositeComponent') 
      : _prodInvariant('136', this.getName() || 'ReactCompositeComponent') 
      : void 0;

    var willReceive = false;
    var nextContext;

    // 更新context
    if (this._context === nextUnmaskedContext) {
      nextContext = inst.context;
    } else {
      nextContext = this._processContext(nextUnmaskedContext);
      willReceive = true;
    }

    var prevProps = prevParentElement.props;
    var nextProps = nextParentElement.props;

    // 包含仅待渲染元素的props变更
    if (prevParentElement !== nextParentElement) {
      willReceive = true;
    }

    // 更新context、或变更带渲染组件元素或其props时willReceive赋值为真,由父组件发起,调用componentWillReceiveProps方法
    if (willReceive && inst.componentWillReceiveProps) {
      if (process.env.NODE_ENV !== 'production') {
        measureLifeCyclePerf(function () {
          return inst.componentWillReceiveProps(nextProps, nextContext);
        }, this._debugID, 'componentWillReceiveProps');
      } else {
        inst.componentWillReceiveProps(nextProps, nextContext);
      }
    }

    // _processPendingState方法获取组件setState、replaceState方法执行后的最终state
    var nextState = this._processPendingState(nextProps, nextContext);
    var shouldUpdate = true;

    // 调用组件的shouldComponentUpdate判断是否需要重绘
    // 纯组件不能设置shouldComponentUpdate方法,仅判断props、state是否变更
    if (!this._pendingForceUpdate) {
      if (inst.shouldComponentUpdate) {
        if (process.env.NODE_ENV !== 'production') {
          shouldUpdate = measureLifeCyclePerf(function () {
            return inst.shouldComponentUpdate(nextProps, nextState, nextContext);
          }, this._debugID, 'shouldComponentUpdate');
        } else {
          shouldUpdate = inst.shouldComponentUpdate(nextProps, nextState, nextContext);
        }
      } else {
        if (this._compositeType === CompositeTypes.PureClass) {
          shouldUpdate = !shallowEqual(prevProps, nextProps) || !shallowEqual(inst.state, nextState);
        }
      }
    }

    // shouldComponentUpdate方法返回undefined,警告
    if (process.env.NODE_ENV !== 'production') {
      process.env.NODE_ENV !== 'production' ? 
        warning(shouldUpdate !== undefined, 
          '%s.shouldComponentUpdate(): Returned undefined instead of a ' 
          + 'boolean value. Make sure to return true or false.', 
          this.getName() || 'ReactCompositeComponent') 
        : void 0;
    }

    this._updateBatchNumber = null;

    // 重绘组件
    if (shouldUpdate) {
      this._pendingForceUpdate = false;

      // 执行componentWillUpdate方法,重绘组件实例render方法内待渲染的子组件,挂载componentDidUpdate方法
      this._performComponentUpdate(nextParentElement, nextProps, nextState, nextContext, transaction, nextUnmaskedContext);
    
    // 只变更组件的部分属性,不开启重绘功能
    } else {
      this._currentElement = nextParentElement;
      this._context = nextUnmaskedContext;
      inst.props = nextProps;
      inst.state = nextState;
      inst.context = nextContext;
    }
  },

  // 获取组件setState、replaceState方法执行后的最终state
  // setState、replaceState方法执行后更迭的state以函数或state数据形式推入_pendingStateQueue中
  _processPendingState: function (props, context) {
    var inst = this._instance;
    var queue = this._pendingStateQueue;
    var replace = this._pendingReplaceState;
    this._pendingReplaceState = false;
    this._pendingStateQueue = null;

    if (!queue) {
      return inst.state;
    }

    if (replace && queue.length === 1) {
      return queue[0];
    }

    var nextState = _assign({}, replace ? queue[0] : inst.state);
    for (var i = replace ? 1 : 0; i < queue.length; i++) {
      var partial = queue[i];
      _assign(nextState, typeof partial === 'function' ? partial.call(inst, nextState, props, context) : partial);
    }

    return nextState;
  },

  // 执行componentWillUpdate方法,重绘组件实例render方法内待渲染的子组件,挂载componentDidUpdate方法
  _performComponentUpdate: function (nextElement, nextProps, nextState, nextContext, transaction, unmaskedContext) {
    var _this2 = this;

    var inst = this._instance;

    var hasComponentDidUpdate = Boolean(inst.componentDidUpdate);
    var prevProps;
    var prevState;
    var prevContext;
    if (hasComponentDidUpdate) {
      prevProps = inst.props;
      prevState = inst.state;
      prevContext = inst.context;
    }

    // 执行componentWillUpdate方法
    if (inst.componentWillUpdate) {
      if (process.env.NODE_ENV !== 'production') {
        measureLifeCyclePerf(function () {
          return inst.componentWillUpdate(nextProps, nextState, nextContext);
        }, this._debugID, 'componentWillUpdate');
      } else {
        inst.componentWillUpdate(nextProps, nextState, nextContext);
      }
    }

    this._currentElement = nextElement;
    this._context = unmaskedContext;
    inst.props = nextProps;
    inst.state = nextState;
    inst.context = nextContext;

    // 以更新子组件的方式或重新创建子组件的方式重绘render方法待渲染的子组件
    this._updateRenderedComponent(transaction, unmaskedContext);

    // 向后置钩子transaction.getReactMountReady()中添加实例的生命周期方法componentDidUpdate
    if (hasComponentDidUpdate) {
      if (process.env.NODE_ENV !== 'production') {
        transaction.getReactMountReady().enqueue(function () {
          measureLifeCyclePerf(inst.componentDidUpdate.bind(inst, prevProps, prevState, prevContext), _this2._debugID, 'componentDidUpdate');
        });
      } else {
        transaction.getReactMountReady().enqueue(inst.componentDidUpdate.bind(inst, prevProps, prevState, prevContext), inst);
      }
    }
  },

  // 以更新子组件的方式或重新创建子组件的方式重绘render方法待渲染的子组件
  _updateRenderedComponent: function (transaction, context) {
    var prevComponentInstance = this._renderedComponent;// 组件render待渲染的子组件实例
    var prevRenderedElement = prevComponentInstance._currentElement;// 子组件元素

    // _renderValidatedComponent方法调用组件实例inst的render方法,获取待挂载的元素
    var nextRenderedElement = this._renderValidatedComponent();

    var debugID = 0;
    if (process.env.NODE_ENV !== 'production') {
      debugID = this._debugID;
    }

    // shouldUpdateReactComponent方法返回真值,更新组件实例;返回否值,销毁实例后、重新创建实例
    // 组件元素的构造函数或key值不同,销毁实例后再行创建

    // render方法子组件构造函数及key相同,通过ReactReconciler.receiveComponent方法更新子组件实例
    if (shouldUpdateReactComponent(prevRenderedElement, nextRenderedElement)) {
      ReactReconciler.receiveComponent(prevComponentInstance, nextRenderedElement, transaction, this._processChildContext(context));
    
    // render方法子组件构造函数或key不同,重新创建子组件实例后,调用_replaceNodeWithMarkup方法替换挂载元素
    } else {
      var oldHostNode = ReactReconciler.getHostNode(prevComponentInstance);
      ReactReconciler.unmountComponent(prevComponentInstance, false);

      var nodeType = ReactNodeTypes.getType(nextRenderedElement);
      this._renderedNodeType = nodeType;
      var child = this._instantiateReactComponent(nextRenderedElement, nodeType !== ReactNodeTypes.EMPTY /* shouldHaveDebugID */
      );
      this._renderedComponent = child;

      var nextMarkup = ReactReconciler.mountComponent(child, transaction, this._hostParent, this._hostContainerInfo, this._processChildContext(context), debugID);

      if (process.env.NODE_ENV !== 'production') {
        if (debugID !== 0) {
          var childDebugIDs = child._debugID !== 0 ? [child._debugID] : [];
          ReactInstrumentation.debugTool.onSetChildren(debugID, childDebugIDs);
        }
      }

      // 替换文档中挂载的Dom元素DomLazyTree
      this._replaceNodeWithMarkup(oldHostNode, nextMarkup, prevComponentInstance);
    }
  },

  // 替换文档中挂载的Dom元素DomLazyTree
  _replaceNodeWithMarkup: function (oldHostNode, nextMarkup, prevInstance) {
    ReactComponentEnvironment.replaceNodeWithMarkup(oldHostNode, nextMarkup, prevInstance);
  },

  // 调用组件实例inst的render方法,获取待挂载的元素
  _renderValidatedComponentWithoutOwnerOrContext: function () {
    var inst = this._instance;
    var renderedElement;

    if (process.env.NODE_ENV !== 'production') {
      renderedElement = measureLifeCyclePerf(function () {
        return inst.render();
      }, this._debugID, 'render');
    } else {
      renderedElement = inst.render();
    }

    if (process.env.NODE_ENV !== 'production') {
      if (renderedElement === undefined && inst.render._isMockFunction) {
        renderedElement = null;
      }
    }

    return renderedElement;
  },

  // 调用组件实例inst的render方法,获取待挂载的元素
  _renderValidatedComponent: function () {
    var renderedElement;
    if (process.env.NODE_ENV !== 'production' || this._compositeType !== CompositeTypes.StatelessFunctional) {
      ReactCurrentOwner.current = this;
      try {
        renderedElement = this._renderValidatedComponentWithoutOwnerOrContext();
      } finally {
        ReactCurrentOwner.current = null;
      }
    } else {
      renderedElement = this._renderValidatedComponentWithoutOwnerOrContext();
    }

    // 校验renderedElement是否为ReactElement
    !(renderedElement === null || renderedElement === false || React.isValidElement(renderedElement)) 
      ? process.env.NODE_ENV !== 'production' ? 
        invariant(false, '%s.render(): A valid React element (or null) must be returned. ' 
          + 'You may have returned undefined, an array or some other invalid object.', 
          this.getName() || 'ReactCompositeComponent') 
        : _prodInvariant('109', this.getName() || 'ReactCompositeComponent') 
      : void 0;

    return renderedElement;
  },

  // 对外提供接口,用于向组件实例ReactComponentInstance添加this.refs属性
  attachRef: function (ref, component) {// 参数component为子组件
    var inst = this.getPublicInstance();

    // 无状态组件没有this.refs属性
    !(inst != null) ? process.env.NODE_ENV !== 'production' ? 
      invariant(false, 'Stateless function components cannot have refs.') 
      : _prodInvariant('110') : void 0;

    var publicComponentInstance = component.getPublicInstance();// 子组件的实例

    // 无状态子组件也不能作为上层组件的this.refs的值
    if (process.env.NODE_ENV !== 'production') {
      var componentName = component && component.getName ? component.getName() : 'a component';
      process.env.NODE_ENV !== 'production' ? 
        warning(publicComponentInstance != null 
          || component._compositeType !== CompositeTypes.StatelessFunctional, 
          'Stateless function components cannot be given refs ' 
          + '(See ref "%s" in %s created by %s). ' + 'Attempts to access this ref will fail.', 
          ref, componentName, this.getName()) 
        : void 0;
    }

    // 通过引用对象的形式赋值inst.refs
    var refs = inst.refs === emptyObject ? inst.refs = {} : inst.refs;
    refs[ref] = publicComponentInstance;
  },

  // 销毁组件实例ReactComponentInstance的refs属性
  detachRef: function (ref) {
    var refs = this.getPublicInstance().refs;
    delete refs[ref];
  },

  // 获取组件名
  getName: function () {
    var type = this._currentElement.type;
    var constructor = this._instance && this._instance.constructor;
    return type.displayName || constructor && constructor.displayName || type.name || constructor && constructor.name || null;
  },

  // 获取组件ReactComponent的实例
  getPublicInstance: function () {
    var inst = this._instance;
    if (this._compositeType === CompositeTypes.StatelessFunctional) {
      return null;
    }
    return inst;
  },

  // 调用instantiateReactComponent模块,用于创建子组件
  _instantiateReactComponent: null

};

module.exports = ReactCompositeComponent;

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值