摘要:在中調(diào)用獲得了的實(shí)例,然后調(diào)用其中的回調(diào)函數(shù)中調(diào)用了方法。這個(gè)類主要介紹其構(gòu)造函數(shù)和方法,構(gòu)造函數(shù)是時(shí)調(diào)用的,方法是的回調(diào)函數(shù)中使用的。這個(gè)將在下一篇分析。另外,方法是在的回調(diào)函數(shù)中調(diào)用的,也是一個(gè)參與后面調(diào)度的關(guān)鍵。
在ReactDOM.render源碼解析-1中介紹了第一次render的基本過(guò)程的一部分,其中產(chǎn)生了ReactRoot和ReactWork兩個(gè)類的實(shí)例。本文介紹下ReactRoot,ReactWork源碼,只關(guān)注第一次調(diào)用render的過(guò)程。回顧
文章中如有不當(dāng)之處,歡迎交流指點(diǎn)。react版本16.8.2。在源碼添加的注釋在githubreact-source-learn。
在上篇分析后,最終得到如下函數(shù)調(diào)用過(guò)程。
在render方法中調(diào)用了legacyRenderSubtreeIntoContainer。
在legacyRenderSubtreeIntoContainer中調(diào)用legacyCreateRootFromDOMContainer獲得了ReactRoot的實(shí)例root,然后調(diào)用unbatchedUpdates,其中的回調(diào)函數(shù)中調(diào)用了root.render方法。RootRoot是什么?他的render方法做了什么?
代碼分析通過(guò)對(duì)ReactRoot和ReactWork代碼的簡(jiǎn)單分析,筆者做了如下類圖,以幫助了解這兩個(gè)類有哪些屬性和方法。
有很多東西不是第一次調(diào)用render用到的,這里只關(guān)注第一次render所需要調(diào)用方法或使用的屬性。
ReactRoot這個(gè)類主要介紹其構(gòu)造函數(shù)和render方法,構(gòu)造函數(shù)是new時(shí)調(diào)用的,render方法是unbatchedUpdates的回調(diào)函數(shù)中使用的。代碼如下:
// ReactRoot構(gòu)造函數(shù) // 構(gòu)造函數(shù)主要是掛了一個(gè)_internalRoot在this上 function ReactRoot( container: DOMContainer, // dom節(jié)點(diǎn) isConcurrent: boolean, // 第一次render為false hydrate: boolean, // 第一次render為false ) { // 這個(gè)createContainer是packages/ReactFiberReconciler中的方法, // 返回的是一個(gè)OpaqueRoot的東西 const root = createContainer(container, isConcurrent, hydrate); this._internalRoot = root; } // render實(shí)例方法 new 了ReactWork, 調(diào)用了then方法 // 調(diào)用了updateContainer方法 // 返回了ReactWork實(shí)例 ReactRoot.prototype.render = function( children: ReactNodeList, // element callback: ?() => mixed, // ReactDOM.render(element, container, callback); callback ): Work { const root = this._internalRoot; const work = new ReactWork(); callback = callback === undefined ? null : callback; if (callback !== null) { work.then(callback); } // updateContainer是packages/react-reconciler/ReactFiberReconciler.js中的 // 一個(gè)方法,后邊再說(shuō) updateContainer(children, root, null, work._onCommit); return work; };
先看構(gòu)造函數(shù)
第一次render時(shí)new ReactRoot位于legacyCreateRootFromDOMContainer中,其調(diào)用代碼如下:
return new ReactRoot(container, isConcurrent, shouldHydrate)。
container是我們調(diào)用ReactDOM.render時(shí)的第二個(gè)參數(shù),一個(gè)dom,但是里邊的子節(jié)點(diǎn)已被處理了,isConcurrent這里是寫死的false,shouldHydrate上文分析過(guò),為false。
再看ReactRoot的構(gòu)造函數(shù),他調(diào)用了一個(gè)createContainer并將返回值掛到了_internalRoot屬性。這個(gè)createContainer將在下一篇分析。
看下render方法
我們先看看第一次render是調(diào)用他的代碼,root.render(children, callback);,其中children是ReactDOM.render的第一個(gè)參數(shù),是個(gè)ReactElement, callback是第三個(gè)參數(shù),通常不傳。
這個(gè)render方法主要做了如下事:
new ReactWork -> work
調(diào)用work的then方法
調(diào)用updateContainer
返回work
這里值得注意的是ReactWork類,這個(gè)將在后文分析;還有updateContainer,這個(gè)將在后面的文章分析,這里搞清楚第一調(diào)用時(shí)的參數(shù)給的啥,即ReactElement,createContainer返回的root,null,ReactWork實(shí)例的_onCommit方法。
ReactWorkReactWork的方法在第一次render時(shí)都有可能被調(diào)用到,如下代碼為ReactWork類的定義:
// ReactWork的構(gòu)造函數(shù) function ReactWork() { this._callbacks = null; this._didCommit = false; // TODO: Avoid need to bind by replacing callbacks in the update queue with // list of Work objects. this._onCommit = this._onCommit.bind(this); } // then方法 ReactWork.prototype.then = function(onCommit: () => mixed): void { if (this._didCommit) { // 第一次render調(diào)用then時(shí)為false, 不走這里 onCommit(); return; } let callbacks = this._callbacks; if (callbacks === null) { // 第一次render是調(diào)用走這里 callbacks = this._callbacks = []; } callbacks.push(onCommit); }; // _onCommit方法 ReactWork.prototype._onCommit = function(): void { if (this._didCommit) { // 第一次render不走這里 return; } this._didCommit = true; // 這個(gè)callbacks是調(diào)用.then方法是傳進(jìn)去的函數(shù) const callbacks = this._callbacks; if (callbacks === null) { return; } // TODO: Error handling. for (let i = 0; i < callbacks.length; i++) { const callback = callbacks[i]; invariant( typeof callback === "function", "Invalid argument passed as callback. Expected a function. Instead " + "received: %s", callback, ); callback(); } };
構(gòu)造函數(shù)
構(gòu)造函數(shù)不接受參數(shù),做了一些初始化工作
then方法
then方法調(diào)用時(shí)是work.then(callback);,callback是ReactDOM的第三個(gè)參數(shù)
then方法的作用就是維護(hù)一個(gè)_callbacks隊(duì)列,每次都將傳進(jìn)去的函數(shù)入隊(duì)
_onCommit方法
這個(gè)方法的調(diào)用代碼updateContainer(children, root, null, work._onCommit),其實(shí)是updateContainer的最后一個(gè)參數(shù)。
在這個(gè)里邊將_didCommit置為true,回顧上邊的ReactRoot的render方法,意味著這個(gè)方法被調(diào)用后在調(diào)ReactRoot.render是會(huì)直接執(zhí)行callback的而不是入隊(duì)。
然后是將_callbacks中的方法都執(zhí)行了一遍。
從上文的分析來(lái)看,接下來(lái)的重點(diǎn)是分析updateContainer這個(gè)方法,ReactWork的then方法是將callback入隊(duì),_onCommit是執(zhí)行_callbacks中的所有方法,而調(diào)用_onCommit的是在updateContainer中,updateContainer實(shí)在ReactRoot.render方法中調(diào)用的,因此updateContainer應(yīng)該是一個(gè)非常重要的東西。另外,ReactRoo.render方法是在unbatchedUpdates的回調(diào)函數(shù)中調(diào)用的,unbatchedUpdates也是一個(gè)參與后面調(diào)度的關(guān)鍵。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/103730.html
摘要:系列文章源碼分析第一篇源碼分析第二篇同步模式源碼分析第三篇異步狀態(tài)源碼分析第四篇?dú)w納總結(jié)前言是在版本中的大更新,利用了閑余時(shí)間看了一些源碼,做個(gè)小記錄流程圖源碼分析先由編譯,調(diào)用,入?yún)椋蛴〕鰜?lái)可以看到,,分別代表著元素原生元素,回調(diào)函數(shù) 系列文章 React Fiber源碼分析 第一篇 React Fiber源碼分析 第二篇(同步模式) React Fiber源碼分析 第三篇(...
摘要:就是,如果你不了解這個(gè)的話可以閱讀下相關(guān)文檔,是應(yīng)用初始化時(shí)就會(huì)生成的一個(gè)變量,值也是,并且這個(gè)值不會(huì)在后期再被改變。這是我的剖析 React 源碼的第三篇文章,如果你沒(méi)有閱讀過(guò)之前的文章,請(qǐng)務(wù)必先閱讀一下 第一篇文章 中提到的一些注意事項(xiàng),能幫助你更好地閱讀源碼。 文章相關(guān)資料 React 16.8.6 源碼中文注釋,這個(gè)鏈接是文章的核心,文中的具體代碼及代碼行數(shù)都是依托于這個(gè)倉(cāng)庫(kù) 熱身...
摘要:本文將對(duì)源碼做一個(gè)初步解析。首先在方法中校驗(yàn)參數(shù)是否合法,然后調(diào)用在中,調(diào)用拿到了的一個(gè)實(shí)例,調(diào)用拿到了,用于注入到,和作為返回值,調(diào)用開(kāi)始調(diào)度過(guò)程在中,首先清理了中的所有子節(jié)點(diǎn),然后了一個(gè)并返回是如何調(diào)度的是一個(gè)什么樣的類的操作是在哪里 初步看了react-dom這個(gè)包的一些源碼,發(fā)現(xiàn)其比react包要復(fù)雜得多,react包中基本不存在跨包調(diào)用的情況,他所做的也僅僅是定義了React...
摘要:查看創(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寫的真的很棒 。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);...
閱讀 1405·2021-11-25 09:43
閱讀 2260·2021-09-27 13:36
閱讀 1114·2021-09-04 16:40
閱讀 1957·2019-08-30 11:12
閱讀 3309·2019-08-29 14:14
閱讀 566·2019-08-28 17:56
閱讀 1320·2019-08-26 13:50
閱讀 1246·2019-08-26 13:29