整個(gè)React工作流程可以分為兩大階段:
-
Render階段
Schecule
Reconcile -
Commit階段
注意,Render階段是在內(nèi)存中運(yùn)行的,這意味者可以被打斷,而commit階段一旦開(kāi)始同步執(zhí)行直到完成。
Renderer工作的階段被稱為commit階段。commit階段可以分為三個(gè)子階段:
before mutation階段(執(zhí)行DOM操作前)
mutation階段(執(zhí)行DOM操作)
layout階段(執(zhí)行DOM操作后)
其中上面的每個(gè)階段又分為三個(gè)子階段:
commit×××Effects
commit×××Effects_begin
commit×××Effects_complete
commit×××Effects:
該函數(shù)是每個(gè)子階段的入口函數(shù),finishedWor會(huì)作為firstChild參數(shù)傳進(jìn)去,相關(guān)代碼如下:
function commit×××Effects(root,firstChild){
nextEffects = firstChild;
// 省略標(biāo)記全局變量
commit×××Effects_begin();
// 省略重置全局變量
}
因此在該函數(shù)中,主要的工作是將firstChild賦值給全局變量nextEffects ,然后執(zhí)行commit×××Effects_begin。
commit×××Effects_begin:
向下遍歷FiberNode,遍歷的時(shí)候直到滿足如下條件之一的FiberNode:
- 當(dāng)前的FiberNode的子FiberNode不包含該子階段對(duì)應(yīng)的flags;
- 當(dāng)前的FiberNode不存在子FiberNode
接下來(lái)會(huì)對(duì)目標(biāo)FiberNode執(zhí)行commit×××Effects_complete方法。
commit×××Effects_complete:
該方法針對(duì)flags做具體的操作,主要包含以下三個(gè)步驟:
- 對(duì)當(dāng)前FiberNode執(zhí)行flags對(duì)應(yīng)的操作,也就是執(zhí)行commit×××EffectsOnFiber
- 對(duì)當(dāng)前FiberNode存在兄弟節(jié)點(diǎn),則對(duì)兄弟節(jié)點(diǎn)執(zhí)行commit×××Effects_begin
- 如不存在兄弟FiberNode,則對(duì)父節(jié)點(diǎn)執(zhí)行commit×××Effects_complete
總結(jié)一下,每個(gè)階段都會(huì)以DFS原進(jìn)行遍歷,最終會(huì)在commit×××EffectsOnFiber針對(duì)不同的flags做出不同的處理。
before mutation階段:
before mutation階段的主要工作發(fā)生在commitBeforeMutationEffects_complete中的commitBeforeMutationEffectsOnFiber方法,這個(gè)方法主要是處理如兩種類型的FiberNode
- ClassComponent:執(zhí)行g(shù)etSnapshotBeforeUpdate
- HostRoot: 清空HostRoot掛載的內(nèi)容,方便mutation階段進(jìn)行渲染;
mutation階段:
對(duì)于HostComponent,mutation階段的主要工作是對(duì)Dom元素的增刪改查
刪除Dom元素
刪除dom的操作發(fā)生在commitMutationsEffects_begin方法中,首先會(huì)拿到deletions數(shù)組,然后遍歷該數(shù)組進(jìn)行刪除操作,對(duì)應(yīng)刪除dom的方法為commitDeletion
commitDeletion(root, nextEffect, renderPriorityLevel);
commitDeletion內(nèi)部的完整邏輯還是比較復(fù)雜的,因?yàn)閯h除一個(gè)dom元素時(shí),不是刪除就刪除的,還需要考慮以下幾點(diǎn):
- 其子樹(shù)中所有組件的unmount邏輯
- 子樹(shù)中所有ref屬性的卸載操作
- 其子樹(shù)中所有Effect相關(guān)的Hook的destory回調(diào)的執(zhí)行
<div>
<SomeClassComponent/>
<div ref={divRef}>
<SomeFunctionsComponents />
</div>
</div>
當(dāng)刪除最外層的div這個(gè)Dom元素時(shí),需要考慮:
- 執(zhí)行SomeClassComponent類組件對(duì)應(yīng)的componentWillUnmount方法,
- 執(zhí)行SomeFunctionsComponents 函數(shù)組件對(duì)應(yīng)的useEffect,useLayoutEffect這些hook中對(duì)應(yīng)的distory方法
- divRef的卸載操作
整個(gè)刪除都是DFS順序,遍歷每個(gè)子樹(shù)的FiberNode,執(zhí)行對(duì)應(yīng)的操作
插入、移動(dòng)Dom元素
上面的刪除是在commitMutationsEffects_begin方法中執(zhí)行的,而插入和移動(dòng)dom元素是在commitMutationsEffects_complete中的commitMutationsEffectsOnFiber方法里面執(zhí)行的
Placement flag對(duì)應(yīng)的操作方法為CommitPlacement,整個(gè)CommitPlacement可以分為三個(gè)步驟:
- 從當(dāng)前FiberNode向上遍歷,獲取第一個(gè)類型為HostComponent,HostRoot,HostPortal三者之一的祖先FiberNode,其對(duì)應(yīng)的Dom元素是執(zhí)行Dom操作的目標(biāo)元素的父級(jí)DOM元素;
- 獲取用于執(zhí)行parentNode.insertBefore(child,before)方法before對(duì)應(yīng)的DOM元素;
- 執(zhí)行parentNode.insertBefore方法(存在before)或者parentNode.appendChild方法(不存在before)
對(duì)于還沒(méi)有插入的DOM元素(對(duì)應(yīng)的就是mount場(chǎng)景),inserBefore會(huì)將目標(biāo)Dom元素插入到before之前,appendChild會(huì)將目標(biāo)DOM元素最為父DOM元素作為父DOM元素的最后一個(gè)子元素插入;
對(duì)于ui中已經(jīng)存在的DOM元素(對(duì)應(yīng)的就是mount場(chǎng)景),inserBefore會(huì)將目標(biāo)Dom元素移動(dòng)到before之前,appendChild會(huì)將目標(biāo)DOM元素移動(dòng)到同級(jí)最后
更新Dom元素
更新dom元素,最主要的工作是更新對(duì)應(yīng)的屬性,執(zhí)行的方法是commitWork;
其中變化的屬性會(huì)以key,value相鄰的形式存在FiberNode.updateQueue,最終在fiberNode.updateQueue里面所保存的要變化的屬性就會(huì)在一個(gè)名為updateDOMProperties方法被遍歷然后進(jìn)行處理,這里的處理主要是處理如下的四種數(shù)據(jù):
- style屬性
- innerHTML
- 直接文本節(jié)點(diǎn)變化
- 其他元素屬性
當(dāng)mutations階段中的主要工作完成后,在進(jìn)入layout階段之前,會(huì)完成Fiber Tree的切換
root.current = finishedWork
layout 階段
有關(guān)dom元素的操作在mutations中已經(jīng)結(jié)束了。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-826318.html
該階段主要工作幾種在commitLayoutEffectOnFiber方法中,在該方法內(nèi)部,會(huì)針對(duì)不同的FiberNode執(zhí)行不同的操作文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-826318.html
- 對(duì)于ClassComponent,該階段執(zhí)行componentDidMount/update方法,
- 對(duì)于FunctionComponent,該階段執(zhí)行useLayoutEffect的回調(diào)函數(shù)。
到了這里,關(guān)于react中commit工作流程的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!