Last Surprise Lyn
  1. 1 Last Surprise Lyn
  2. 2 Life Will Change Lyn
  3. 3 かかってこいよ NakamuraEmi
  4. 4 Quiet Storm Lyn
  5. 5 Libertus Chen-U
  6. 6 Hypocrite Nush
  7. 7 One Last You Jen Bird
  8. 8 Flower Of Life 发热巫女
  9. 9 The Night We Stood Lyn
  10. 10 Warcry mpi
  11. 11 Time Bomb Veela
2018-04-05 22:02:20

React源码解析——生命周期的管理

我们已经知道了根据render方法传入参数的不同,在react内部会生成4种不同类型的自定义组件,但生命周期只存在于ReactCompositeComponent组件中,这篇文章就来分析该类组件来探讨生命周期的注册原理。

mountComponent

组件挂载时会根据类型调用其基类的mountComponent方法,源码如下:

var ReactCompositeComponentMixin = {
    construct:function(element){
        //...
    },

    mountComponent: function (transaction, hostParent, hostContainerInfo, context) {
      // 处理传入props和组件类型参数
        var publicProps = this._currentElement.props;
        var Component = this._currentElement.type;
        var updateQueue = transaction.getUpdateQueue();

        // 初始化公共类
        var doConstruct = shouldConstruct(Component);
        var inst = this._constructComponent(doConstruct, publicProps, publicContext, updateQueue);
        var renderedElement;

        // 判断无状态组件
        if (!doConstruct && (inst == null || inst.render == null)) {
            renderedElement = inst;
            warnIfInvalidElement(Component, renderedElement);
            inst = new StatelessComponent(Component);
            this._compositeType = CompositeTypes.StatelessFunctional;
        } else {
            if (isPureComponent(Component)) {
                this._compositeType = CompositeTypes.PureClass;
            } else {
                this._compositeType = CompositeTypes.ImpureClass;
            }
        }

        inst.props = publicProps;
        inst.context = publicContext;
        inst.refs = emptyObject;
        inst.updater = updateQueue;

        this._instance = inst;
        // 将实例存储为引用
        ReactInstanceMap.set(inst, this);
        // 初始化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;

          // 初始化挂载
        var markup;
        if (inst.unstable_handleError) {
            markup = this.performInitialMountWithErrorHandling(renderedElement, hostParent, hostContainerInfo, transaction, context);
        } else {
            markup = this.performInitialMount(renderedElement, hostParent, hostContainerInfo, transaction, context);
        }
        // 挂载结束后执行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;
  },
}

该方法首先处理props和组件类型,接着根据传入组件类是否包含render方法来判断其是否为无状态组件,如果是无状态组件则不会初始化状态更新队列,只专注于渲染。

接着将实例存储为一个引用到ReactInstanceMap中,再初始化更新队列后就准备挂载组件了。挂载组件完成后就会触发componentDidMount的生命周期方法,下面来看挂载的流程。

performInitialMount

挂载的主要方法为performInitialMount,源码如下:

performInitialMount: function(renderedElement, nativeParent, nativeContainerInfo, transaction, context) {
    var inst = this._instance;
  // 处理componentWillMount生命周期
  if (inst.componentWillMount) {
      inst.componentWillMount();
    // componentWillMount调用setState时不会rerender而是合并
    if (this._pendingStateQueue) {
        inst.state = this._processPendingState(inst.props, inst.context);
    }
  }
  // 无状态组件判断
  if (renderedElement === undefined) {
      renderedElement = this._renderValidatedComponent();
  }
  this._renderedNodeType = ReactNodeTypes.getType(renderedElement);
  // 得到对应component类实例
  this._renderedComponent = this._instantiateReactComponent(renderedElement);
  // 递归渲染子组件
  var markup = ReactReconciler.mountComponent(this._renderedComponent, transaction, nativeParent, nativeContainerInfo, this._processChildContext(context));

  return markup;
}

在这个阶段内会首先调用componentWillMount生命周期方法,然后判断是否为无状态组件。如果不是无状态组件则调用其render生命周期方法得到renderedElement,再调用instantiateReactComponent方法,其作用是根据不同的组件类型参数调用相对应的方法创建实例。源码如下:

function instantiateReactComponent(node, shouldHaveDebugID) {
  var instance;
  if (node === null || node === false) {
    instance = ReactEmptyComponent.create(instantiateReactComponent);
  } else if (typeof node === 'object') {
    var element = node;

    if (typeof element.type === 'string') {
        instance = ReactHostComponent.createInternalComponent(element);
    } else if (isInterbalComponentType(element.type)) {
        instance = new element.type(element);
          if (!instance.getHostNode) {
            instance.getHostNode = instance.getNativeNode;
        }
    } else {
        instance = new ReactCompositeComponentWrapper(element);
    }
  } else if (typeof node === 'string' || typeof node === 'number') {
    instance = ReactHostComponent.createInstanceForText(node);
  }
  instance._mountIndex = 0;
  instance._mountImage = null;

  return instance;
}

ReactCompositeComponent组件会由ReactCompositeComponentWrapper创建,也就是其基类的构造方法了。最后再递归渲染子组件进行同样的初始化和挂载流程。到这里也可以看出react应用是递归的渲染内容的,即父组件的componentWillMount在子组件之前,componentDidMount在子组件之后。

update的生命周期流程和mount的生命周期流程的思想一致,就不在此赘述。

-- EOF --

添加在分类「 前端开发 」下,并被添加 「React」 标签。