React生命週期能夠分爲掛載、更新、卸載三個階段。主要能夠分爲兩類:react
組件的掛載是最基本過程,這個過程主要作初始化。在這初始化個過程當中componentWillMount會在render方法以前執行,而componentDidMount方法會在render方法以後執行。分別表明了渲染先後時刻。寫一個簡單的例子:app
class Demo extends React.Component { static propTypes = {} static defaultProps = {} constructor(props) { super(props) this.state = {} } componentWillMount() {} render() {return null} componentDidMount() {} }
如上,這個初始化過程沒有什麼特別之處,這裏包括讀取初始state、讀取初始props、以及兩個生命週期方法componentWillMount和componentDidMount。這些都只會在組件初始化時執行一次。less
組件的卸載只有componentWillUnmount這個一個方法。異步
組件的更新發生在父組件傳遞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。
前面大體介紹了組件的生命週期主要分爲三種狀態:掛載、更新、卸載。以下圖能夠詳細瞭解不一樣狀態的執行順序:oop
使用ES6 classes構建組件的時候static defaultProps={}其實就是調用內部的getDefaultProps方法。constructor中的this.state={}其實就是調用內部的getInitialState方法。this
自定義組件生命週期經過3個階段進行控制:MOUNTING,RECEIVE_PROPS,UNMOUNTING,它負責通知組件當時所處的階段,應該執行生命週期中的哪一個步驟。這三個階段分別對應三個方法:spa
createClass是建立自定義組件的入口方法,負責管理生命週期中的getDefaultProps方法。該方法在整個生命週期中只執行一次,這樣全部實例初始化的props都能共享。
經過createClass建立自定義組件,利用原型繼承ReactClassComponent父類,按順序合併mixin,設置初始化defaultProps,返回構造函數。prototype
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; }, }
mountComponent負責管理生命週期中的getInitialState,componentWillMount,render和componentDidMount。
因爲getDefaultProps是在初始化構造函數中進行管理的,因此也是整個生命週期中最早執行的。並且只執行一次也能夠理解了。3d
因爲經過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 = 1 var 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; } }
updateComponent負責管理生命週期的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在其子組件以後執行。
unmountComponent負責管理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); },