當首次掛載組件時,按順序執行 getDefaultProps、getInitialState、componentWillMount、 render 和 componentDidMount。
當卸載組件時,執行 componentWillUnmount。
當從新掛載組件時,此時按順序執行 getInitialState、componentWillMount、render 和 componentDidMount,但並不執行 getDefaultProps。
當再次渲染組件時,組件接受到更新狀態,此時按順序執行 componentWillReceiveProps、 shouldComponentUpdate、componentWillUpdate、render 和 componentDidUpdatejavascript
class MyComponent extends React.Component 其實就 是調用內部方法 createClass 建立組件
調用getDefaultProps。
因爲 getDefaultProps 是經過構造函數進行管理的,因此也是整個生命週期中先開始執行的java
若存在 componentWillMount,則執行。若是此時在 componentWillMount 中調用 setState 方法,不會觸發re-render,會進行state合併,而且this.state不是最新的。算法
若是此時在 componentWillReceiveProps 中調 用 setState,是不會觸發 re-render的,而是會進行 state 合併。
updateComponent 本質上也是經過遞歸渲染內容的,因爲遞歸的特性,父組件的 component- WillUpdate 是在其子組件的 componentWillUpdate 以前調用的,而父組件的 componentDidUpdate 也是在其子組件的 componentDidUpdate 以後調用的
禁止在 shouldComponentUpdate 和 componentWillUpdate 中調用 setState,這會形成循環調用,直至耗光瀏覽器內存後崩潰數組
若是存在 componentWillUnmount,則執行並重置全部相關參數、更新隊列以及更新狀態,如 果此時在 componentWillUnmount 中調用 setState,是不會觸發 re-render 的,這是由於全部更新 隊列和更新狀態都被重置爲 null瀏覽器
無狀態組件
只有一個render方法app
調用setState -> 新state進入隊列 -> 合併更新隊列 -> 判斷是否在批量更新 -> 若是在,component放入dirtyComponent等待下一次更新;若是不在,進行批量更新函數
ReactComponent.prototype.setState = function(partialState, callback) { this.updater.enqueueSetState(this, partialState); //更新state if (callback) {//回調函數 this.updater.enqueueCallback(this, callback, 'setState'); } };
enqueueSetState中,合併更新隊列,調用enqueueUpdatethis
function enqueueUpdate(component) { // 不處於批量更新模式,進行更新 if (!batchingStrategy.isBatchingUpdates) { batchingStrategy.batchedUpdates(enqueueUpdate, component); //批處理更新 return; } // 處於批量更新模式 dirtyComponents.push(component); }
事務(Transaction)
事務就是將須要執行的方法使用 wrapper 封裝起來,再經過事務提供的 perform 方法執行。 而在 perform 以前,先執行全部 wrapper 中的 initialize 方法,執行完 perform 以後(即執行 method 方法後)再執行全部的 close 方法。一組 initialize 及 close 方法稱爲一個 wrapper。
而要使用事務的模 塊,除了須要把 mixin 混入本身的事務實現中外,還要額外實現一個抽象的 getTransactionWrappers 接口。這個接口用來獲取全部須要封裝的前置方法(initialize)和收尾方法(close), 所以它須要返回一個數組的對象,每一個對象分別有 key 爲 initialize 和 close 的方法prototype
perform (func, scope,a,b,c,d,e,f){ this.initializeAll(0); method.call(scope, a, b, c, d, e, f); this.closeAll(0); }
Diff算法本質上是對javascript對象之間的比較,只有在React更新階段(調用了setState)纔會有Diff算法的運用。
流程:code
_receivePropsAndState: function(nextProps, nextState, transaction)
if (!this.shouldComponentUpdate || //沒有定義shouldComponentUpdate函數 this.shouldComponentUpdate(nextProps, nextState)) { //shouldComponentUpdate函數返回true this._performComponentUpdate(nextProps, nextState, transaction); } else { //shouldComponentUpdate函數返回了false,不進行DOM更新,只更新props和state的值 this.props = nextProps; this.state = nextState; }
4.this._performComponentUpdate(nextProps, nextState, transaction);
調用this.componentWillUpdate
this.updateComponent(transaction);
調用this.componentDidUpdate
5.this.updateComponent(transaction)
updateComponent: function(transaction) { var currentComponent = this._renderedComponent; //原組件 var nextComponent = this._renderValidatedComponent(); //新組件 //兩個組件的類相同(構造函數同樣) if (currentComponent.constructor === nextComponent.constructor) { if (!nextComponent.props.isStatic) { currentComponent.receiveProps(nextComponent.props, transaction); //更新組件 } } else { // 兩個組件的類不同,直接替換 var thisID = this._rootNodeID; var currentComponentID = currentComponent._rootNodeID; //卸載原組件 currentComponent.unmountComponent(); //加載新組件 var nextMarkup = nextComponent.mountComponent(thisID, transaction); ReactComponent.DOMIDOperations.dangerouslyReplaceNodeWithMarkupByID( currentComponentID, nextMarkup ); this._renderedComponent = nextComponent; }
}
有三種類型的component:
①文本 ReactTextComponent
receiveProps: function(nextProps, transaction) { //text不同直接替換 if (nextProps.text !== this.props.text) { this.props.text = nextProps.text; ReactComponent.DOMIDOperations.updateTextContentByID( this._rootNodeID, nextProps.text ); } }
②React自定義組件
調用componentWillReceiveProps
再次調用this._receivePropsAndState(nextProps, nextState, transaction);
tree diff
比較兩棵DOM樹,若是某個節點不存在,則該節點及其子節點會被徹底刪除,不會進一步比較。 React只會簡單地考慮同層級節點的位置變換
component diff
若是是同一類型組件,繼續比較
若是不是,替換整個組件
對於同一類型的組件,有可能其 Virtual DOM 沒有任何變化,若是可以確切知道這點,那 麼就能夠節省大量的 diff 運算時間。所以,React 容許用戶經過 shouldComponentUpdate() 來判斷該組件是否須要進行 diff 算法分析。
element diff
1.比較新舊集合元素的key,若是有相同key,說明舊集合中有新集合的元素。
2.若是該元素在舊集合的index < lastIndex (lastindex指的是訪問過的元素在舊集合中最大的index),移動該元素到nextIndex,不然不移動。
3.若是新集合裏的元素在舊集合不存在,建立新元素到當前index。
4.更新lastIndex, nextIndex++
存在的缺陷《深刻React技術棧》做者觀點是:若是舊集合是A,B,C,D, 新集合是D,A,B,CD不會移動,而ABC都要依次移動。實際上D只要移動到C後面本人認爲:A,B,C的index都已經發生變化,因此確定會有移動操做,避免不了。