`

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
0
分享到:
评论

相关推荐

    微信小程序商城系统源码

    微信小程序 商城 (源码)微信小程序 商城 (源码)微信小程序 商城 (源码)微信小程序 商城 (源码)微信小程序 商城 (源码)微信小程序 商城 (源码)微信小程序 商城 (源码)微信小程序 商城 (源码)微信小程序 商城 (源码)...

    SSCOM源码 DELPHI 源码

    SSCOM源码 DELPHI 源码 绝对源码!欢迎下载

    微信小程序源码下载 微信小程序源码下载 2000套微信小程序源码

    本资源包含2000套微信小程序的源码,对于开发者来说是一份宝贵的参考资料,可以用来学习、研究或者作为开发新项目的起点。 源码下载是开发者获取程序原始代码的方式,对于学习和理解编程逻辑至关重要。这些微信小...

    饿了么源码 百度外卖源码 美团外卖源码 外卖系统源码

    订餐网,外卖网源码,带积分商城,商家系统,外卖网站建设! 系统特点: 周密策划、项目为先 "项目指导技术,技术服从项目",这是我们一贯秉承的原则,也是我们与其他系统开发商、网站建设公司的本质区别所在!我们...

    变速齿轮 易语言源码 变速齿轮源码 变速器源码

    易语言源码就是用这种语言编写的程序代码,通过阅读和理解这些源码,开发者可以学习到如何利用易语言来实现特定功能,比如变速齿轮。 在易语言中实现变速齿轮功能,主要涉及到以下几个关键知识点: 1. **系统时间...

    移动医疗APP源码 android (安卓版)妙手医生源码

    移动医疗APP源码是开发医疗健康应用的核心组成部分,它包含了应用程序的所有逻辑和界面设计。在Android平台上,这种源码通常是用Java或Kotlin语言编写的,并使用Android Studio作为集成开发环境(IDE)。在这个案例...

    ssh框架项目源码ssh框架项目源码ssh框架项目源码

    ssh框架项目源码ssh框架项目源码ssh框架项目源码ssh框架项目源码ssh框架项目源码ssh框架项目源码ssh框架项目源码ssh框架项目源码ssh框架项目源码ssh框架项目源码ssh框架项目源码ssh框架项目源码ssh框架项目源码ssh...

    cocos creator完整麻将源码下载

    《cocos creator完整麻将源码解析与开发指南》 cocos Creator是一款强大的2D游戏开发引擎,被广泛应用于游戏开发,尤其是休闲娱乐类游戏,如麻将。本篇将深入探讨"麻将源码"这一主题,结合cocos Creator的特性,为...

    51套经典企业网站源码(一)

    0001-2科技发展有限公司升级版源码 0001科技发展有限公司修正版源码 0002机械配件制造销售公司修正版源码 0003家具地板公司修正版源码 0004-1机械有限公司修正版源码 0004机械有限公司修正版源码 0005机械产品公司...

    捕鱼游戏源码 下载 最新完整版

    捕鱼游戏源码是一种基于计算机编程技术,用于开发模拟海洋捕鱼场景的电子游戏的代码集合。这类源码通常包含了游戏逻辑、图形渲染、音频处理、用户交互等多个方面的详细实现,为开发者提供了一个深入理解游戏开发过程...

    53客服系统源码 53kf源码

    在源码层面,53客服系统源码主要包含了以下几个关键知识点: 1. **多平台支持**:53客服系统通常支持网页、手机APP、微信等多种渠道的接入,源码中会有相应的接口实现,以确保用户可以通过不同的终端与客服进行交互...

    仿58同城赶集网源码

    分类源码,信息发布网站源码,信息源码,信息港网站源码,asp信息港源码,信息类网站源码,多种分类源码,信息网源码下载,asp信息网源码,信息发布系统源码,物流信息源码,房产信息网源码.net源码,公安信息网源码,家教信息...

    非常漂亮的个人博客网站源码

    标题中的“非常漂亮的个人博客网站源码”表明这是一个关于个人博客网站的设计与开发资源,它包含了一套完整的源代码,可以用于创建一个美观且个性化的博客平台。这种源码通常包括HTML、CSS、JavaScript等前端代码,...

    Linux系统下dhcp源码

    Linux系统下的DHCP(Dynamic Host Configuration Protocol)源码解析 DHCP是一种网络协议,用于自动分配IP地址、子网掩码、默认网关等网络配置信息给网络中的设备。在Linux环境中,DHCP服务器通常使用isc-dhcp-...

    DIY个性T恤定制网站源码

    【DIY个性T恤定制网站源码】是一个用于创建在线个性化商品定制平台的软件系统,主要专注于T恤、杯子、台历和挂历等产品。这个源码允许用户通过简单的界面设计自己的产品,体现个人风格和创意。接下来,我们将深入...

    机顶盒聚合视频桌面源码

    本话题聚焦于一个特殊的软件组件——“机顶盒聚合视频桌面源码”,这是一种为机顶盒定制的用户界面(UI)和应用,它整合了多个视频来源,如直播频道和点播服务。 聚合视频桌面源码是开发机顶盒应用的核心部分,它的...

    多功能在线报价系统源码

    【标题】:“多功能在线报价系统源码” 在线报价系统是一种基于网络的应用程序,它使得企业或个人能够方便快捷地提供产品或服务的价格信息给潜在客户。这个“多功能在线报价系统源码”是专为此目的设计的,允许用户...

    net-tools arp源码 ifconfig源码 route源码

    net-tools arp源码 ifconfig源码 route源码

    2021新版神算子网络付费测算源码算命网站源码测算网站源码

    算命源码,神算子网络网高级版付费源码完整版,下载后请根据文档进行安装,数据库可在线恢复,本版本为学习使用,禁止商业用途,如需商用,请移步神算子网络购买正版.

    公司产品展示网站源码

    【产品展示网站源码】是一种用于在线展示公司产品的软件代码,它构成了一个网站的基础结构,允许企业以有吸引力的方式向访客展示其商品或服务。此类源码通常包含前端和后端组件,前者负责用户界面的设计和交互,后者...

Global site tag (gtag.js) - Google Analytics