装载组件触发 (componentWillMount,componentDidMount)

componentWillMount(只会在装载之前调用一次,在 render 前调用,可以在这个方法里面调用 setState 改变状态,并且不会导致额外调用一次 render),render,componentDidMount(在装载完成之后调用一次,在 render 后调用,从这里开始可以通过 ReactDOM.findDOMNode(this) 获取到组件的 DOM 节点)都是在mountComponent中被调用。

不同的React组件的mountComponent实现都有所区别(之前提过有多种ReactElement)。这里以ReactCompositeComponent的mountComponent为例说明(代码位置:src/renderers/shared/stack/reconciler/ReactCompositeComponent.js):

mountComponent: function(
    transaction,
    hostParent,
    hostContainerInfo,
    context,
  ) {
    this._context = context;
    this._mountOrder = nextMountID++;
    this._hostParent = hostParent;
    this._hostContainerInfo = hostContainerInfo;

    var publicProps = this._currentElement.props;
    var publicContext = this._processContext(context);

    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;
      if (__DEV__) { ... }
      invariant( ... );
      inst = new StatelessComponent(Component);
      this._compositeType = ReactCompositeComponentTypes.StatelessFunctional;
    } else {
      if (isPureComponent(Component)) {
        this._compositeType = ReactCompositeComponentTypes.PureClass;
      } else {
        this._compositeType = ReactCompositeComponentTypes.ImpureClass;
      }
    }

    if (__DEV__) { ... }

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

      warning( ... );
    }

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

    this._instance = inst;

    ReactInstanceMap.set(inst, this);

    if (__DEV__) { ... }

    // 这里设置了 initialState
    var initialState = inst.state;
    if (initialState === undefined) {
      inst.state = initialState = null;
    }
    invariant( ... );

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

    if (inst.componentWillMount) {
      if (__DEV__) {
        measureLifeCyclePerf(
          () => inst.componentWillMount(),
          this._debugID,
          'componentWillMount',
        );
      } else {
        // 这里执行了componentWillMount()
        inst.componentWillMount();
      }

      if (this._pendingStateQueue) {
        inst.state = this._processPendingState(inst.props, inst.context);
      }
    }

    var markup;
    if (inst.componentDidCatch) {
      markup = this.performInitialMountWithErrorHandling(
        renderedElement,
        hostParent,
        hostContainerInfo,
        transaction,
        context,
      );
    } else {
      markup = this.performInitialMount(
        renderedElement,
        hostParent,
        hostContainerInfo,
        transaction,
        context,
      );
    }

    if (inst.componentDidMount) {
      if (__DEV__) {
        transaction.getReactMountReady().enqueue(() => {
          measureLifeCyclePerf(
            () => inst.componentDidMount(),
            this._debugID,
            'componentDidMount',
          );
        });
      } else {
     // 这里执行了 componentDidMount       transaction.getReactMountReady().enqueue(inst.componentDidMount, inst);
      }
    }

    //在willMount执行的 setState的回调函数会在这里调用
    const callbacks = this._pendingCallbacks;
    if (callbacks) {
      this._pendingCallbacks = null;
      for (let i = 0; i < callbacks.length; i++) {
        transaction.getReactMountReady().enqueue(callbacks[i], inst);
      }
    }

    return markup;
  }

更新组件触发(componentWillReceiveProps,shouldComponentUpdate,componentWillUpdate,componentDidUpdate)

这些方法不会在首次 render 组件的周期调用,当组件的状态发生变化时(比如通过setState修改了组件的state)会触发组件的更新,这些逻辑会在updateComponent中调用,也就是说组件更新的逻辑主要是在updateComponent方法中。

仍然以ReactCompositeComponent的updateComponent方法为例(代码位置:src/renderers/shared/stack/reconciler/ReactCompositeComponent.js):

updateComponent: function(
    transaction,
    prevParentElement,
    nextParentElement,
    prevUnmaskedContext,
    nextUnmaskedContext,
  ) {
    var inst = this._instance;
    invariant( ... );

    var willReceive = false;
    var nextContext;

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

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

    // Not a simple state update but a props update
    if (prevParentElement !== nextParentElement) {
      willReceive = true;
    }

    if (willReceive && inst.componentWillReceiveProps) {
      const beforeState = inst.state;
      if (__DEV__) {
        ...
      } else {
    // 这里调用了componentWillReceiveProps()       inst.componentWillReceiveProps(nextProps, nextContext);
      }
      const afterState = inst.state;
      if (beforeState !== afterState) {
        inst.state = beforeState;
        inst.updater.enqueueReplaceState(inst, afterState);
        if (__DEV__) {
         ...
        }
      }
    }

    var callbacks = this._pendingCallbacks;
    this._pendingCallbacks = null;

    var nextState = this._processPendingState(nextProps, nextContext);
    var shouldUpdate = true;
    if (!this._pendingForceUpdate) {
      var prevState = inst.state;
      shouldUpdate = willReceive || nextState !== prevState;
      if (inst.shouldComponentUpdate) {
        if (__DEV__) {
          ...
        } else {
        //这里用到了shouldComponentUpdate
          shouldUpdate = inst.shouldComponentUpdate(
            nextProps,
            nextState,
            nextContext,
          );
        }
      } else {
        if (this._compositeType === ReactCompositeComponentTypes.PureClass) {
          shouldUpdate =
            !shallowEqual(prevProps, nextProps) ||
            !shallowEqual(inst.state, nextState);
        }
      }
    }

    if (__DEV__) {
      ...
    }

    this._updateBatchNumber = null;

    //如果shouldUpdate为true,则执行更新渲染
    if (shouldUpdate) {
      this._pendingForceUpdate = false;
      // 执行更新渲染的逻辑
      this._performComponentUpdate(
        nextParentElement,
        nextProps,
        nextState,
        nextContext,
        transaction,
        nextUnmaskedContext,
      );
    } else {
      this._currentElement = nextParentElement;
      this._context = nextUnmaskedContext;
      inst.props = nextProps;
      inst.state = nextState;
      inst.context = nextContext;
    }

    if (callbacks) {
      for (var j = 0; j < callbacks.length; j++) {
        transaction
          .getReactMountReady()
          .enqueue(callbacks[j], this.getPublicInstance());
      }
    }
  }

通过上面代码可以看出,updateComponent中执行了componentWillReceiveProps和shouldComponentUpdate逻辑,最后shouldUpdate为true进行更新渲染时调用的是 _performComponentUpdate,来看 _performComponentUpdate的源码(位置同上):

_performComponentUpdate: function(
    nextElement,
    nextProps,
    nextState,
    nextContext,
    transaction,
    unmaskedContext,
  ) {
    var inst = this._instance;

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

    if (inst.componentWillUpdate) {
      if (__DEV__) {
        ...
      } else {
      // 这里执行了componentWillUpdate
        inst.componentWillUpdate(nextProps, nextState, nextContext);
      }
    }

    // 重新设置state props等属性
    this._currentElement = nextElement;
    this._context = unmaskedContext;
    inst.props = nextProps;
    inst.state = nextState;
    inst.context = nextContext;

    if (inst.componentDidCatch) {
      this._updateRenderedComponentWithErrorHandling(
        transaction,
        unmaskedContext,
      );
    } else {
      // 调用render方法,重新解析ReactElement并得到HTML
      this._updateRenderedComponent(transaction, unmaskedContext);
    }

    if (hasComponentDidUpdate) {
      if (__DEV__) {
        ...
      } else {
        // 这里执行了componentDidUpdate
        transaction
          .getReactMountReady()
          .enqueue(
            inst.componentDidUpdate.bind(inst, prevProps, prevState),
            inst,
          );
      }
    }
  }

可以看到_performComponentUpdate中执行了componentWillUpdate(更新render前),componentDidUpdate(更新render后),至此,更新组件触发的生命周期函数就齐了。

卸载组件触发(componentWillUnmount)

卸载组件时,主要的逻辑是在unmountComponent方法(更新组件时如果不满足DOM diff条件,也会先unmountComponent, 然后再mountComponent。),来看下unmountComponent源码(以ReactCompositeComponent为例,位置同上):

unmountComponent: function(safely, skipLifecycle) {
    if (!this._renderedComponent) {
      return;
    }

    var inst = this._instance;

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

      if (safely) {
        if (!skipLifecycle) {
          var name = this.getName() + '.componentWillUnmount()';
          ReactErrorUtils.invokeGuardedCallbackAndCatchFirstError(
            name,
            inst.componentWillUnmount,
            inst,
          );
        }
      } else {
        if (__DEV__) {
          ...
        } else {
          // 这里执行了componentWillUnmount
          inst.componentWillUnmount();
        }
      }
    }

    // 递归调用unMountComponent来销毁子组件
    if (this._renderedComponent) {
      ReactReconciler.unmountComponent(
        this._renderedComponent,
        safely,
        skipLifecycle,
      );
      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);
  }

可以看到在unmountComponent里调用componentWillUnmount(),然后递归调用unmountComponent(),最后销毁子组件将内部变量置空,防止内存泄漏。

至此,React的生命周期就基本能理清了,其他几种类型的React Component也类似,这里不在赘述,有兴趣可以看下源码。

results matching ""

    No results matching ""