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