初步了解React生命周期React生命周期可以分为挂载、更新、卸载三个阶段。主要可以分为两类:组件挂载和卸载;组件接收新的数据和状态时的更新;1.1 组件的挂载组件的挂载是最基本过程,这个过程主要做初始化。在这初始化个过程中componentWillMount会在render方法之前执行,而componentDidMount方法会在render方法之后执行。分别代表了渲染前后时刻。写一个简单的例子:class Demo extends React.Component { static propTypes = {} static defaultProps = {} constructor(props) { super(props) this.state = {} } componentWillMount() {} render() {return null} componentDidMount() {}}如上,这个初始化过程没有什么特别之处,这里包括读取初始state、读取初始props、以及两个生命周期方法componentWillMount和componentDidMount。这些都只会在组件初始化时执行一次。1.2 组件的卸载组件的卸载只有componentWillUnmount这个一个方法。1.3 组件的更新组件的更新发生在父组件传递props或者自身执行setState改变状态这一系列操作的情况下。和组件更新的生命周期方法有以下几个:class Demo extends React.Component { //当组件更新时会顺序执行以下方法 componentWillReceiveProps(nextProps){} // shouldComponentUpdate(nextProps, nextState) {} //返回false则停止向下执行,默认返回true componentWillUpdate(nextProps, nextState) {} render() {} componentDidUpdate(prevProps, prevState) {}}tip: shouldComponentUpdate可以用来正确的渲染组件的。理想情况下,父级节点改变时,只会重新渲染一条链路上和该props相关的组件。但是默认情况下,React会渲染所有的节点,因为shouldComponentUpdate默认返回true。2. 深入了解React生命周期前面大致介绍了组件的生命周期主要分为三种状态:挂载、更新、卸载。如下图可以详细了解不同状态的执行顺序:使用ES6 classes构建组件的时候static defaultProps={}其实就是调用内部的getDefaultProps方法。constructor中的this.state={}其实就是调用内部的getInitialState方法。2.1 详解React生命周期自定义组件生命周期通过3个阶段进行控制:MOUNTING,RECEIVE_PROPS,UNMOUNTING,它负责通知组件当时所处的阶段,应该执行生命周期中的哪个步骤。这三个阶段分别对应三个方法:2.2使用createClass创建自定义组件createClass是创建自定义组件的入口方法,负责管理生命周期中的getDefaultProps方法。该方法在整个生命周期中只执行一次,这样所有实例初始化的props都能共享。通过createClass创建自定义组件,利用原型继承ReactClassComponent父类,按顺序合并mixin,设置初始化defaultProps,返回构造函数。var ReactClass = { createClass: function(spec) { var Constructor = function(props, context, updater) { // 自动绑定 if (this.__reactAutoBindPairs.length) { bindAutoBindMethods(this); } this.props = props; this.context = context; this.refs = emptyObject; this.updater = updater || ReactNoopUpdateQueue; this.state = null; //ReactClasses没有构造函数,通过getInitialState和componentWillMount来代替 var initialState = this.getInitialState ? this.getInitialState() : null; this.state = initialState; }; //原型继承ReactClassComponent父类 Constructor.prototype = new ReactClassComponent(); Constructor.prototype.constructor = Constructor; Constructor.prototype.__reactAutoBindPairs = []; //合并mixin injectedMixins.forEach( mixSpecIntoComponent.bind(null, Constructor) ); mixSpecIntoComponent(Constructor, spec); //所有mixin合并后初始化defaultProps(在生个生命周期中,defaultProps只执行一次) if (Constructor.getDefaultProps) { Constructor.defaultProps = Constructor.getDefaultProps(); } //设置原型 for (var methodName in ReactClassInterface) { if (!Constructor.prototype[methodName]) { Constructor.prototype[methodName] = null; } } //最后返回的是构造函数 return Constructor; },}2.3 阶段一:MOUNTINGmountComponent负责管理生命周期中的getInitialState,componentWillMount,render和componentDidMount。由于getDefaultProps是在初始化构造函数中进行管理的,所以也是整个生命周期中最先执行的。而且只执行一次也可以理解了。由于通过ReactCompositeComponentBase返回的是一个虚拟节点,所以需要通过 instantiate-ReactComponent去得到实例,在通过mountComponent拿到结果作为当前自定义元素的结果。通过mountComponent挂载组件,初始化序号,标记参数等,判断是否为无状态组件,并进行对应的初始化操作,比如初始化props,context等参数。利用getInitialState获取初始化state, 初始化更新队列和更新状态。如果存在componentWillMount则执行,如果此时在componetWillMount调用setState方法,是不会触发re-render方法,而是会进行state合并,且inst.state = this._processPendingState(inst.props, inst.context)在componentWillMount之后执行。因此在render中才可以获取到最新的state。因此,React是通过更新队列this._pendingStateQueue以及更新状态this._pendingReeplaceState和this._pendingForUpdate来实现setState的异步更新。当渲染完成后,若存在componentDidMount则调用。其实mountComponent是通过递归渲染内容。由于递归的特性,父组件的componentWillMount在其子组件的componentWillMount之前调用,父组件的componentDidMount在其子组件的componentDidMount之后调用。//react/src/renderers/shared/reconciler/ReactCompositeComponent.js//当组件挂载时,会分配一个递增编号,表示执行ReactUpdates时更新组件的顺序var nextMountID = 1var ReactCompositeComponentMixin = { //初始化组件,渲染标记,注册事件监听器 mountComponent: function (transaction, nativeParent, nativeContainerInfo, context) { this._context = context; //当前组件对应的上下文 this._mountOrder = nextMountID++; this._nativeParent = nativeParent; this._nativeContainerInfo = nativeContainerInfo; var publicProps = this._processProps(this._currentElement.props); var publicContext = this._processContext(context); var Component = this._currentElement.type; // 初始化公共类 var inst; var renderedElement; //这里判断是否是无状态组件,无状态组件没有更新状态序列,只关注更新 if (Component.prototype && Component.prototype.isReactComponent) { inst = new Component(publicProps, publicContext, ReactUpdateQueue); } else { inst = Component(publicProps, publicContext, ReactUpdateQueue); if (inst == null || inst.render == null) { renderedElement = inst; warnIfInvalidElement(Component, renderedElement); invariant( inst === null || inst === false || ReactElement.isValidElement(inst), ‘%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’ ); inst = new StatelessComponent(Component); } } // These should be set up in the constructor, but as a convenience for // simpler class abstractions, we set them up after the fact. //这些初始化参数应该在构造函数中设置,再此处设置为了便于简单的类抽象 inst.props = publicProps; inst.context = publicContext; inst.refs = emptyObject; inst.updater = ReactUpdateQueue; this._instance = inst; // 将实例存储为一个引用 ReactInstanceMap.set(inst, this); //初始化state var initialState = inst.state; if (initialState === undefined) { inst.state = initialState = null; } //初始化state更新队列 this._pendingStateQueue = null; this._pendingReplaceState = false; this._pendingForceUpdate = false; var markup; //如果挂载错误则执行performInitialMountWithErrorHandling(方法如下) if (inst.unstable_handleError) { markup = this.performInitialMountWithErrorHandling( renderedElement, nativeParent, nativeContainerInfo, transaction, context ); } else { //执行挂载 markup = this.performInitialMount(renderedElement, nativeParent, nativeContainerInfo, transaction, context); } //如果存在componentDidMount则调用 if (inst.componentDidMount) { transaction.getReactMountReady().enqueue(inst.componentDidMount, inst); } return markup; }, //挂载错误执行方法 performInitialMountWithErrorHandling: function ( renderedElement, nativeParent, nativeContainerInfo, transaction, context ) { var markup; var checkpoint = transaction.checkpoint(); try { //如果没有错误则初始化挂载 markup = this.performInitialMount(renderedElement, nativeParent, nativeContainerInfo, 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) { this._instance.state = this._processPendingState(this._instance.props, this._instance.context); } checkpoint = transaction.checkpoint(); //如果捕捉到错误,则执行unmountComponent后再初始化挂载 this._renderedComponent.unmountComponent(true); transaction.rollback(checkpoint); markup = this.performInitialMount(renderedElement, nativeParent, nativeContainerInfo, transaction, context); } return markup; }, //初始化挂载方法 performInitialMount: function(renderedElement, nativeParent, nativeContainerInfo, transaction, context) { var inst = this._instance; //如果存在componentWillMount则调用 if (inst.componentWillMount) { inst.componentWillMount(); //如果在componentWillMount触发setState时,不会触发re-render,而是自动提前合并 if (this._pendingStateQueue) { inst.state = this._processPendingState(inst.props, inst.context); } } // 如果不是无状态组件则直接渲染 if (renderedElement === undefined) { renderedElement = this._renderValidatedComponent(); } this._renderedNodeType = ReactNodeTypes.getType(renderedElement); //得到 _currentElement对应的component类实例 this._renderedComponent = this._instantiateReactComponent( renderedElement ); //递归渲染 var markup = ReactReconciler.mountComponent( this._renderedComponent, transaction, nativeParent, nativeContainerInfo, this._processChildContext(context) ); return markup; }}2.4 阶段二:REVEIVE_PROPSupdateComponent负责管理生命周期的componentWillReceiveProps、shouldComponent、componentWillUpdate、render、componentDidUpdate。首先通过updateComponent更新组件,如果前后元素不一致,说明需要组件更新。若存在componentWillReceiveProps,则执行。如果此时在componentWillReceiveProps中调用setState是不会触发re-render,而是会进行state合并。且在componentWillReceiveProps,shouldComponentUpate和componentWillUpdate是无法获取更新后的this.state。需要设置inst.state = nextState后才可以。因此只有在render和componentDidUpdate中才可以获取更新后的state.调用shouldComponentUpdate判断是否需要进行组件更新,如果存在componentWillUpdate则执行。updateComponet也是通过递归渲染的,由于递归的特性,父组件的componentWillUpdate在子组件之前执行,父组件的componentDidUpdate在其子组件之后执行。2.5 阶段三:UNMOUNTINGunmountComponent负责管理componentWillUnmount。在这个阶段会清空一切。//组件卸载 unmountComponent: function(safely) { if (!this._renderedComponent) { return; } var inst = this._instance; //如果存在componentWillUnmount,则调用 if (inst.componentWillUnmount) { if (safely) { var name = this.getName() + ‘.componentWillUnmount()’; ReactErrorUtils.invokeGuardedCallback(name, inst.componentWillUnmount.bind(inst)); } else { inst.componentWillUnmount(); } } //如果组件已经渲染,则对组件进行unmountComponent操作 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 = null; this._topLevelWrapper = null; //清除公共类 ReactInstanceMap.remove(inst); },