摘要:生命周期當(dāng)首次掛載組件時(shí),按順序執(zhí)行和。由于是通過(guò)構(gòu)造函數(shù)進(jìn)行管理的,所以也是整個(gè)生命周期中先開(kāi)始執(zhí)行的加載組件若存在,則執(zhí)行。一組及方法稱為一個(gè)。因此,允許用戶通過(guò)來(lái)判斷該組件是否需要進(jìn)行算法分析。
生命周期
? 當(dāng)首次掛載組件時(shí),按順序執(zhí)行 getDefaultProps、getInitialState、componentWillMount、 render 和 componentDidMount。
? 當(dāng)卸載組件時(shí),執(zhí)行 componentWillUnmount。
? 當(dāng)重新掛載組件時(shí),此時(shí)按順序執(zhí)行 getInitialState、componentWillMount、render 和 componentDidMount,但并不執(zhí)行 getDefaultProps。
? 當(dāng)再次渲染組件時(shí),組件接受到更新?tīng)顟B(tài),此時(shí)按順序執(zhí)行 componentWillReceiveProps、 shouldComponentUpdate、componentWillUpdate、render 和 componentDidUpdate
創(chuàng)建自定義組件
class MyComponent extends React.Component 其實(shí)就 是調(diào)用內(nèi)部方法 createClass 創(chuàng)建組件
調(diào)用getDefaultProps。
由于 getDefaultProps 是通過(guò)構(gòu)造函數(shù)進(jìn)行管理的,所以也是整個(gè)生命周期中先開(kāi)始執(zhí)行的
MOUNTING(加載組件)
若存在 componentWillMount,則執(zhí)行。如果此時(shí)在 componentWillMount 中調(diào)用 setState 方法,不會(huì)觸發(fā)re-render,會(huì)進(jìn)行state合并,并且this.state不是最新的。
RECEIVE_PROPS(更新組件)
如果此時(shí)在 componentWillReceiveProps 中調(diào) 用 setState,是不會(huì)觸發(fā) re-render的,而是會(huì)進(jìn)行 state 合并。
updateComponent 本質(zhì)上也是通過(guò)遞歸渲染內(nèi)容的,由于遞歸的特性,父組件的 component- WillUpdate 是在其子組件的 componentWillUpdate 之前調(diào)用的,而父組件的 componentDidUpdate 也是在其子組件的 componentDidUpdate 之后調(diào)用的
禁止在 shouldComponentUpdate 和 componentWillUpdate 中調(diào)用 setState,這會(huì)造成循環(huán)調(diào)用,直至耗光瀏覽器內(nèi)存后崩潰
UNMOUNTING(卸載組件)
如果存在 componentWillUnmount,則執(zhí)行并重置所有相關(guān)參數(shù)、更新隊(duì)列以及更新?tīng)顟B(tài),如 果此時(shí)在 componentWillUnmount 中調(diào)用 setState,是不會(huì)觸發(fā) re-render 的,這是因?yàn)樗懈?隊(duì)列和更新?tīng)顟B(tài)都被重置為 null
無(wú)狀態(tài)組件
只有一個(gè)render方法
setState
調(diào)用setState -> 新state進(jìn)入隊(duì)列 -> 合并更新隊(duì)列 -> 判斷是否在批量更新 -> 如果在,component放入dirtyComponent等待下一次更新;如果不在,進(jìn)行批量更新
ReactComponent.prototype.setState = function(partialState, callback) { this.updater.enqueueSetState(this, partialState); //更新state if (callback) {//回調(diào)函數(shù) this.updater.enqueueCallback(this, callback, "setState"); } };
enqueueSetState中,合并更新隊(duì)列,調(diào)用enqueueUpdate
function enqueueUpdate(component) { // 不處于批量更新模式,進(jìn)行更新 if (!batchingStrategy.isBatchingUpdates) { batchingStrategy.batchedUpdates(enqueueUpdate, component); //批處理更新 return; } // 處于批量更新模式 dirtyComponents.push(component); }
事務(wù)(Transaction)
事務(wù)就是將需要執(zhí)行的方法使用 wrapper 封裝起來(lái),再通過(guò)事務(wù)提供的 perform 方法執(zhí)行。 而在 perform 之前,先執(zhí)行所有 wrapper 中的 initialize 方法,執(zhí)行完 perform 之后(即執(zhí)行 method 方法后)再執(zhí)行所有的 close 方法。一組 initialize 及 close 方法稱為一個(gè) wrapper。
而要使用事務(wù)的模 塊,除了需要把 mixin 混入自己的事務(wù)實(shí)現(xiàn)中外,還要額外實(shí)現(xiàn)一個(gè)抽象的 getTransactionWrappers 接口。這個(gè)接口用來(lái)獲取所有需要封裝的前置方法(initialize)和收尾方法(close), 因此它需要返回一個(gè)數(shù)組的對(duì)象,每個(gè)對(duì)象分別有 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算法本質(zhì)上是對(duì)javascript對(duì)象之間的比較,只有在React更新階段(調(diào)用了setState)才會(huì)有Diff算法的運(yùn)用。
流程:
this.setState(partialState) 更新state
this.replaceState(completeState) 合并state
this._receivePropsAndState(this.props,nextState,transaction)收到新的props和state,決定是否更新組件
_receivePropsAndState: function(nextProps, nextState, transaction)
if (!this.shouldComponentUpdate || //沒(méi)有定義shouldComponentUpdate函數(shù) this.shouldComponentUpdate(nextProps, nextState)) { //shouldComponentUpdate函數(shù)返回true this._performComponentUpdate(nextProps, nextState, transaction); } else { //shouldComponentUpdate函數(shù)返回了false,不進(jìn)行DOM更新,只更新props和state的值 this.props = nextProps; this.state = nextState; }
4.this._performComponentUpdate(nextProps, nextState, transaction);
調(diào)用this.componentWillUpdate
this.updateComponent(transaction);
調(diào)用this.componentDidUpdate
5.this.updateComponent(transaction)
updateComponent: function(transaction) { var currentComponent = this._renderedComponent; //原組件 var nextComponent = this._renderValidatedComponent(); //新組件 //兩個(gè)組件的類相同(構(gòu)造函數(shù)一樣) if (currentComponent.constructor === nextComponent.constructor) { if (!nextComponent.props.isStatic) { currentComponent.receiveProps(nextComponent.props, transaction); //更新組件 } } else { // 兩個(gè)組件的類不一樣,直接替換 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自定義組件
調(diào)用componentWillReceiveProps
再次調(diào)用this._receivePropsAndState(nextProps, nextState, transaction);
tree diff
比較兩棵DOM樹(shù),如果某個(gè)節(jié)點(diǎn)不存在,則該節(jié)點(diǎn)及其子節(jié)點(diǎn)會(huì)被完全刪除,不會(huì)進(jìn)一步比較。 React只會(huì)簡(jiǎn)單地考慮同層級(jí)節(jié)點(diǎn)的位置變換
component diff
如果是同一類型組件,繼續(xù)比較
如果不是,替換整個(gè)組件
對(duì)于同一類型的組件,有可能其 Virtual DOM 沒(méi)有任何變化,如果能夠確切知道這點(diǎn),那 么就可以節(jié)省大量的 diff 運(yùn)算時(shí)間。因此,React 允許用戶通過(guò) shouldComponentUpdate() 來(lái)判斷該組件是否需要進(jìn)行 diff 算法分析。
element diff
1.比較新舊集合元素的key,如果有相同key,說(shuō)明舊集合中有新集合的元素。
2.如果該元素在舊集合的index < lastIndex (lastindex指的是訪問(wèn)過(guò)的元素在舊集合中最大的index),移動(dòng)該元素到nextIndex,否則不移動(dòng)。
3.如果新集合里的元素在舊集合不存在,創(chuàng)建新元素到當(dāng)前index。
4.更新lastIndex, nextIndex++
存在的缺陷
《深入React技術(shù)棧》作者觀點(diǎn)是:
如果舊集合是A,B,C,D, 新集合是D,A,B,C
D不會(huì)移動(dòng),而ABC都要依次移動(dòng)。
實(shí)際上D只要移動(dòng)到C后面
本人認(rèn)為:A,B,C的index都已經(jīng)發(fā)生變化,所以肯定會(huì)有移動(dòng)操作,避免不了。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/98068.html
摘要:查看創(chuàng)建核心函數(shù)源碼行調(diào)用函數(shù)創(chuàng)建是相關(guān),不用管源碼行這個(gè)指的是調(diào)用創(chuàng)建,下面我們將會(huì)說(shuō)到對(duì)象源碼行源碼行函數(shù)中,首先創(chuàng)建了一個(gè),然后又創(chuàng)建了一個(gè),它們兩者還是相互引用。 感謝 yck: 剖析 React 源碼解析,本篇文章是在讀完他的文章的基礎(chǔ)上,將他的文章進(jìn)行拆解和加工,加入我自己的一下理解和例子,便于大家理解。覺(jué)得yck寫(xiě)的真的很棒 。React 版本為 16.8.6,關(guān)于源碼的...
摘要:一更新的方式有三種渲染接下來(lái),我們就來(lái)看下源碼二作用在提供的里渲染一個(gè)元素,并返回對(duì)該組件的引用常見(jiàn)的用法是這個(gè)官網(wǎng)網(wǎng)址源碼服務(wù)端使用方法渲染節(jié)點(diǎn)是讓服務(wù)端盡可能復(fù)用節(jié)點(diǎn),提高性能元素容器應(yīng)用渲染結(jié)束后,調(diào)用的函數(shù)錯(cuò)誤抓取方法本質(zhì)是返回 showImg(https://segmentfault.com/img/remote/1460000020064414?w=1240&h=641);...
摘要:一作用獲取目標(biāo)的實(shí)例使用源碼可修改的不可變的對(duì)象沒(méi)見(jiàn)過(guò)這種寫(xiě)法初始化對(duì)象,屬性初始值為解析源碼比較簡(jiǎn)單,就是返回了帶有屬性的二作用從父組件中獲取子組件是的實(shí)例使用是沒(méi)有實(shí)例的,因?yàn)樗牵詻](méi)有,所以不能通過(guò)來(lái)拿到實(shí)例將的傳給子組件,并綁定 showImg(https://segmentfault.com/img/remote/1460000019877636); 一、React.cr...
摘要:司徒正美的一款了不起的化方案,支持到。行代碼內(nèi)實(shí)現(xiàn)一個(gè)胡子大哈實(shí)現(xiàn)的作品其實(shí)就是的了源碼學(xué)習(xí)個(gè)人文章源碼學(xué)習(xí)個(gè)人文章源碼學(xué)習(xí)個(gè)人文章源碼學(xué)習(xí)個(gè)人文章這幾片文章的作者都是司徒正美,全面的解析和官方的對(duì)比。 前言 在過(guò)去的一個(gè)多月中,為了能夠更深入的學(xué)習(xí),使用React,了解React內(nèi)部算法,數(shù)據(jù)結(jié)構(gòu),我自己,從零開(kāi)始寫(xiě)了一個(gè)玩具框架。 截止今日,終于可以發(fā)布第一個(gè)版本,因?yàn)榫驮谧蛱欤?..
摘要:一例子看到一個(gè)有趣的現(xiàn)象,就是多層嵌套的數(shù)組經(jīng)過(guò)后,平鋪成了,接下來(lái)以該例解析二作用源碼進(jìn)行基本的判斷和初始化后,調(diào)用該方法就是重命名了,即解析注意,該數(shù)組在里面滾了一圈后,會(huì)結(jié)果三作用的包裹器源碼第一次第二次如果字符串中有連續(xù)多個(gè)的話 showImg(https://segmentfault.com/img/remote/1460000019968077?w=1240&h=698);...
閱讀 3407·2023-04-26 02:41
閱讀 2455·2023-04-26 00:14
閱讀 2862·2021-08-11 10:22
閱讀 1284·2019-12-27 11:38
閱讀 3576·2019-08-29 18:34
閱讀 2384·2019-08-29 12:13
閱讀 2955·2019-08-26 18:26
閱讀 1855·2019-08-26 16:49