摘要:生命周期當首次掛載組件時,按順序執行和。由于是通過構造函數進行管理的,所以也是整個生命周期中先開始執行的加載組件若存在,則執行。一組及方法稱為一個。因此,允許用戶通過來判斷該組件是否需要進行算法分析。
生命周期
? 當首次掛載組件時,按順序執行 getDefaultProps、getInitialState、componentWillMount、 render 和 componentDidMount。
? 當卸載組件時,執行 componentWillUnmount。
? 當重新掛載組件時,此時按順序執行 getInitialState、componentWillMount、render 和 componentDidMount,但并不執行 getDefaultProps。
? 當再次渲染組件時,組件接受到更新狀態,此時按順序執行 componentWillReceiveProps、 shouldComponentUpdate、componentWillUpdate、render 和 componentDidUpdate
創建自定義組件
class MyComponent extends React.Component 其實就 是調用內部方法 createClass 創建組件
調用getDefaultProps。
由于 getDefaultProps 是通過構造函數進行管理的,所以也是整個生命周期中先開始執行的
MOUNTING(加載組件)
若存在 componentWillMount,則執行。如果此時在 componentWillMount 中調用 setState 方法,不會觸發re-render,會進行state合并,并且this.state不是最新的。
RECEIVE_PROPS(更新組件)
如果此時在 componentWillReceiveProps 中調 用 setState,是不會觸發 re-render的,而是會進行 state 合并。
updateComponent 本質上也是通過遞歸渲染內容的,由于遞歸的特性,父組件的 component- WillUpdate 是在其子組件的 componentWillUpdate 之前調用的,而父組件的 componentDidUpdate 也是在其子組件的 componentDidUpdate 之后調用的
禁止在 shouldComponentUpdate 和 componentWillUpdate 中調用 setState,這會造成循環調用,直至耗光瀏覽器內存后崩潰
UNMOUNTING(卸載組件)
如果存在 componentWillUnmount,則執行并重置所有相關參數、更新隊列以及更新狀態,如 果此時在 componentWillUnmount 中調用 setState,是不會觸發 re-render 的,這是因為所有更新 隊列和更新狀態都被重置為 null
無狀態組件
只有一個render方法
setState
調用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中,合并更新隊列,調用enqueueUpdate
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 的方法
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算法
Diff算法本質上是對javascript對象之間的比較,只有在React更新階段(調用了setState)才會有Diff算法的運用。
流程:
this.setState(partialState) 更新state
this.replaceState(completeState) 合并state
this._receivePropsAndState(this.props,nextState,transaction)收到新的props和state,決定是否更新組件
_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; }
}
currentComponent.receiveProps(nextComponent.props, transaction)
有三種類型的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,C
D不會移動,而ABC都要依次移動。
實際上D只要移動到C后面
本人認為:A,B,C的index都已經發生變化,所以肯定會有移動操作,避免不了。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/98068.html
摘要:查看創建核心函數源碼行調用函數創建是相關,不用管源碼行這個指的是調用創建,下面我們將會說到對象源碼行源碼行函數中,首先創建了一個,然后又創建了一個,它們兩者還是相互引用。 感謝 yck: 剖析 React 源碼解析,本篇文章是在讀完他的文章的基礎上,將他的文章進行拆解和加工,加入我自己的一下理解和例子,便于大家理解。覺得yck寫的真的很棒 。React 版本為 16.8.6,關于源碼的...
摘要:一更新的方式有三種渲染接下來,我們就來看下源碼二作用在提供的里渲染一個元素,并返回對該組件的引用常見的用法是這個官網網址源碼服務端使用方法渲染節點是讓服務端盡可能復用節點,提高性能元素容器應用渲染結束后,調用的函數錯誤抓取方法本質是返回 showImg(https://segmentfault.com/img/remote/1460000020064414?w=1240&h=641);...
摘要:一作用獲取目標的實例使用源碼可修改的不可變的對象沒見過這種寫法初始化對象,屬性初始值為解析源碼比較簡單,就是返回了帶有屬性的二作用從父組件中獲取子組件是的實例使用是沒有實例的,因為它是,所以沒有,所以不能通過來拿到實例將的傳給子組件,并綁定 showImg(https://segmentfault.com/img/remote/1460000019877636); 一、React.cr...
摘要:司徒正美的一款了不起的化方案,支持到。行代碼內實現一個胡子大哈實現的作品其實就是的了源碼學習個人文章源碼學習個人文章源碼學習個人文章源碼學習個人文章這幾片文章的作者都是司徒正美,全面的解析和官方的對比。 前言 在過去的一個多月中,為了能夠更深入的學習,使用React,了解React內部算法,數據結構,我自己,從零開始寫了一個玩具框架。 截止今日,終于可以發布第一個版本,因為就在昨天,我...
摘要:一例子看到一個有趣的現象,就是多層嵌套的數組經過后,平鋪成了,接下來以該例解析二作用源碼進行基本的判斷和初始化后,調用該方法就是重命名了,即解析注意,該數組在里面滾了一圈后,會結果三作用的包裹器源碼第一次第二次如果字符串中有連續多個的話 showImg(https://segmentfault.com/img/remote/1460000019968077?w=1240&h=698);...
閱讀 3416·2023-04-26 02:41
閱讀 2472·2023-04-26 00:14
閱讀 2891·2021-08-11 10:22
閱讀 1295·2019-12-27 11:38
閱讀 3583·2019-08-29 18:34
閱讀 2390·2019-08-29 12:13
閱讀 2964·2019-08-26 18:26
閱讀 1878·2019-08-26 16:49