您好,登錄后才能下訂單哦!
本文小編為大家詳細(xì)介紹“useEffect返回函數(shù)執(zhí)行過(guò)程是什么”,內(nèi)容詳細(xì),步驟清晰,細(xì)節(jié)處理妥當(dāng),希望這篇“useEffect返回函數(shù)執(zhí)行過(guò)程是什么”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來(lái)學(xué)習(xí)新知識(shí)吧。
下面是源碼簡(jiǎn)化:
function recursivelyTraversePassiveUnmountEffects(parentFiber: Fiber): void { const deletions = parentFiber.deletions; if ((parentFiber.flags & ChildDeletion) !== NoFlags) { if (deletions !== null) { for (let i = 0; i < deletions.length; i++) { const childToDelete = deletions[i]; nextEffect = childToDelete; commitPassiveUnmountEffectsInsideOfDeletedTree_begin( childToDelete, parentFiber ); } } } } function commitPassiveUnmountEffectsInsideOfDeletedTree_begin( deletedSubtreeRoot: Fiber, nearestMountedAncestor: Fiber | null ) { while (nextEffect !== null) { const fiber = nextEffect; // 執(zhí)行 passive effects 返回的函數(shù) commitPassiveUnmountInsideDeletedTreeOnFiber(fiber, nearestMountedAncestor); const child = fiber.child; if (child !== null) { child.return = fiber; nextEffect = child; } else { commitPassiveUnmountEffectsInsideOfDeletedTree_complete( deletedSubtreeRoot ); } } } function commitPassiveUnmountEffectsInsideOfDeletedTree_complete( deletedSubtreeRoot ) { while (nextEffect !== null) { const fiber = nextEffect; const sibling = fiber.sibling; const returnFiber = fiber.return; if (fiber === deletedSubtreeRoot) { nextEffect = null; return; } if (sibling !== null) { sibling.return = returnFiber; nextEffect = sibling; return; } nextEffect = returnFiber; } }
在正式開(kāi)始之前,我們要了解一個(gè) fiber
的屬性:deletions
這個(gè)屬性存放的是當(dāng)前節(jié)點(diǎn)中被刪除的 fiber
,這個(gè)數(shù)組是在 commit
階段被賦值的
如果有被刪除的節(jié)點(diǎn),這個(gè)屬性值是一個(gè)數(shù)組,如果沒(méi)有被刪除的節(jié)點(diǎn),這個(gè)屬性值是 null
const A = () => { useEffect(() => { return () => { console.log("A unmount"); }; }, []); return <div>文本A</div>; }; const B = () => { useEffect(() => { return () => { console.log("B unmount"); }; }, []); return <div>文本B</div>; };
如果 App
組件這樣寫(xiě),那么 deletions
的值是 [FiberNode, FiberNode]
const App(){ const [count, setCount] = useState(0) return <div> {count % 2 === 0 && <A />} {count % 2 === 0 && <B />} <div onClick={()=> setCount(count+1)}>+1</div> </div> }
如果 App
組件這樣寫(xiě),那么 deletions
的值是 [FiberNode]
const App(){ const [count, setCount] = useState(0) return <div> {count % 2 === 0 && <><A /><B /></>} <div onClick={()=> setCount(count+1)}>+1</div> </div> }
對(duì)于第二種情況,react
會(huì)把 A
組件和 B
組件作為一個(gè)整體,所以 deletions
的值是 [FiberNode]
react
在遍歷 fiber tree
時(shí),會(huì)先處理當(dāng)前的 fiber
的 deletions
,等處理完之后再遍歷下一個(gè) fiber
現(xiàn)在我們已經(jīng)知道 deletions
中保存的是當(dāng)前 fiber
下被刪除的子節(jié)點(diǎn)
這時(shí) react
會(huì)遍歷 deletions
數(shù)組,然后執(zhí)行每個(gè) fiber
的 passive effect
返回的函數(shù)
但是有個(gè)問(wèn)題,如果 deletions
中的 fiber
有子節(jié)點(diǎn),那么這些子節(jié)點(diǎn)也會(huì)被刪除,這時(shí) react
會(huì)怎么處理呢?
這里分兩種情況來(lái)討論:
刪除的 fiber
沒(méi)有子節(jié)點(diǎn):<div>{xxxx && <A />}</div>
刪除的 fiber
有子節(jié)點(diǎn):<div>{xxxx && <><A /><B /></>}</div>
-->
<div>{xxxx && <A />}</div>
這種情況比較好理解
當(dāng)遍歷到 div
時(shí),因?yàn)?<A/>
節(jié)點(diǎn)會(huì)被卸載,所以在 div
的 deletions
保存了一個(gè) <A/>
的 fiber
遍歷 deletions
數(shù)組,執(zhí)行 <A/>
的 passive effect
返回的函數(shù)
如下圖所示:
<div>{xxxx && <><A /><B /></>}</div>
這種情況就比較復(fù)雜了
當(dāng)遍歷到 div
時(shí),<></>
節(jié)點(diǎn)會(huì)被卸載,所以在 div
的 deletions
保存了一個(gè) <></>
的 fiber
遍歷 deletions
數(shù)組,執(zhí)行 fiber
的 passive effect
返回的函數(shù),對(duì)于 <></>
來(lái)說(shuō)是不存在的 passive effect
那么這個(gè)時(shí)候就要去遍歷它的 child.fiber
,也就是 <A/>
和 <B/>
首先拿到第一個(gè) fiber,也就是 <A/>
,然后執(zhí)行 <A/>
的 passive effect
返回的函數(shù),這步比較好理解
child = fiber.child; if (child !== null) { nextEffect = child; }
這里遍歷也是深度優(yōu)先,遍歷一個(gè) child
,執(zhí)行一個(gè) passive effect
返回函數(shù),然后再遍歷下一個(gè) child
(這邊 <A />
已經(jīng)是葉子節(jié)點(diǎn)了)
然后拿到第二個(gè) fiber
,也就是 <B/>
,然后執(zhí)行 <B/>
的 passive effect
返回的函數(shù),這步就不太好理解了
child = fiber.child; if (child !== null) { nextEffect = child; } else { commitPassiveUnmountEffectsInsideOfDeletedTree_complete(deletedSubtreeRoot); }
這里要注意的是:
react
在尋找有 passive effect
的 fiber
時(shí),只遍歷到有 passive effect
的 fiber
, 像 div
這種沒(méi)有 passive effect
就不會(huì)遍歷
但是在處理 deletions
,react
會(huì)遍歷所有的 fiber
,也就是說(shuō)從當(dāng)前的 fiber
開(kāi)始,一直往下遍歷到葉子節(jié)點(diǎn),這個(gè)葉子節(jié)點(diǎn)是指文本節(jié)點(diǎn)這種,往下不會(huì)有節(jié)點(diǎn)了(對(duì)于 A
組件來(lái)說(shuō) 文本A
是文本節(jié)點(diǎn))
然后在開(kāi)始往上遍歷,往上遍歷是調(diào)用 commitPassiveUnmountEffectsInsideOfDeletedTree_complete
函數(shù),直到遍歷到 deletionRoot
,在向上遍歷的過(guò)程中會(huì)檢查是否有 sibling
,如果有說(shuō)明 sibling
還沒(méi)被處理,這樣就找到了 <B/>
,然后執(zhí)行 <B/>
的 passive effect
返回的函數(shù)
如下圖所示:
在處理 deletions
時(shí),對(duì)于每個(gè) deletedNode
,都先向下遍歷,然后再向上遍歷
向下遍歷:commitPassiveUnmountEffectsInsideOfDeletedTree_begin
(深度優(yōu)先,優(yōu)先處理左邊的節(jié)點(diǎn))
向上遍歷:commitPassiveUnmountEffectsInsideOfDeletedTree_complete
(之后再處理右邊節(jié)點(diǎn))
react
在處理 deletions
時(shí),先沿著 fiber tree
向下遍歷,如果有 passive effect
返回的函數(shù),則執(zhí)行
一直遍歷到?jīng)]有 child
的 fiber
,再向上遍歷,處理 sibling
再向上遍歷時(shí),如果如果遇到 sibling
,再向下遍歷,向下遍歷時(shí)遇到 passive effect
返回的函數(shù),則執(zhí)行
如此循環(huán)直到遍歷到 deletedNode
,結(jié)束遍歷
遍歷尋找有 passive effect
節(jié)點(diǎn)
react
從根組件向下遍歷,如果沒(méi)有 passive effect
,則不會(huì)遍歷
遍歷時(shí),如果遇到當(dāng)前節(jié)點(diǎn)有 deletions
時(shí),會(huì)暫停尋找 passive effect
節(jié)點(diǎn)
進(jìn)入遍歷 deletions
數(shù)組
圖中綠色部分是遍歷 deletionsNode
過(guò)程,紅色部分是遍歷尋找 passive effect
過(guò)程
讀到這里,這篇“useEffect返回函數(shù)執(zhí)行過(guò)程是什么”文章已經(jīng)介紹完畢,想要掌握這篇文章的知識(shí)點(diǎn)還需要大家自己動(dòng)手實(shí)踐使用過(guò)才能領(lǐng)會(huì),如果想了解更多相關(guān)內(nèi)容的文章,歡迎關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。