一文掌握React?組件樹遍歷技巧
引言
本文對應(yīng)的 react
版本是 18.2.0
下面的 dom
結(jié)構(gòu)react
內(nèi)部是如何遍歷的
const App = () => { return ( <div> <button>+1</button> <A count={0} /> </div> ); }; const A = (props) => { useEffect(() => { console.log(props.count); }, [props.count]); return <div>{props.count}</div>; };
react 內(nèi)部遍歷核心邏輯:
- 在
render
時調(diào)用commitPassiveUnmountOnFiber
函數(shù) commitPassiveUnmountOnFiber
處理不同的WorkTag
,并調(diào)用recursivelyTraversePassiveUnmountEffects
recursivelyTraversePassiveUnmountEffects
根據(jù)當(dāng)前Fiber
的子節(jié)點有沒有passive effect
(useEffect
,useLayoutEffect
)來決定是否遍歷當(dāng)前Fiber
的子節(jié)點- 如果子節(jié)點有
passive effect
,則優(yōu)先遍歷子節(jié)點 (深度優(yōu)先),直到找到最終的葉子節(jié)點,退出當(dāng)前循環(huán) - 然后進入兄弟節(jié)點,開始遍歷兄弟節(jié)點的子節(jié)點
- 具體從哪個兄弟節(jié)點開始遍歷,
react
選擇的是離退出循環(huán)的那個葉子節(jié)點的父節(jié)點,檢查有沒有子節(jié)點,以此循環(huán)遍歷
- 具體從哪個兄弟節(jié)點開始遍歷,
- 直到最后找到所有有
passive effect
的節(jié)點
- 如果子節(jié)點有
commitPassiveUnmountOnFiber(root.current); function commitPassiveUnmountOnFiber(finishedWork) { // 省略了處理不同的 WorkTag recursivelyTraversePassiveUnmountEffects(finishedWork); } function recursivelyTraversePassiveUnmountEffects(parentFiber) { // 省略了其他處理 if (parentFiber.subtreeFlags & PassiveMask) { let child = parentFiber.child; while (child !== null) { commitPassiveUnmountOnFiber(child); child = child.sibling; } } }
所以對于這段 dom 的遍歷邏輯是:
- 首先從根組件開始
FiberRootNode
,取到current
- 也就是說
FiberRootNode.current
是div#root
這是一個fiber
,它的tag
是3
- 也就是說
- 由于
App
的子組件有passive effect
,所以會進入App
組件,它的tag
是0
App
組件中節(jié)點是<div>
,<di >
的tag
是5
<div>
下面有兩個子元素<button>
、<A>
- 先遍歷
<button>
它的tag
是5
<button>
內(nèi)部只有一個文本節(jié)點,沒有passive effect
- 所以
react
不遍歷了(跳出當(dāng)前遍歷的循環(huán),也就是button
這條不在遍歷了)
- 所以
- 跳出循環(huán)后,查看
button
的兄弟節(jié)點,它的兄弟節(jié)點是<A>
,<A>
的tag
是0
- 由于
<A>
節(jié)點的子節(jié)點沒有passive effect
,所以跳出循環(huán),結(jié)束整個遍歷
總結(jié)
- 從跟節(jié)點開始遍歷
- 當(dāng)前組件的子組件有沒有
passive effect
- 采取深度優(yōu)先
- 如果
dom
節(jié)點內(nèi)有函數(shù)組件,則這個dom
會被遍歷,否則不會遍歷 - 如果當(dāng)前
fiber
下的所有子fiber
都沒有passive effect
,則這一整個都鏈表都不會被遍歷 - 如果當(dāng)前
fiber
只有dom
,則這些dom
也不會遍歷
總的來說組件會不會別遍歷看 fiber
有沒有 passive effect
:
- 有,一定會被遍歷
- 沒有,下面兩種情況會被遍歷,其他情況不會被遍歷
- 是
passive effect
的父組件 - 和
passive effect
組件是兄弟組件
- 是
passive effect
指的是 useEffect
,useLayoutEffect
遍歷邏輯如下圖所示
圖中畫綠色勾的都會被遍歷,紅色勾是遍歷的順序
以上就是一文掌握React 組件樹遍歷技巧的詳細內(nèi)容,更多關(guān)于React 組件樹遍歷的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
關(guān)于React動態(tài)修改元素樣式的三種方式
這篇文章主要介紹了關(guān)于React動態(tài)修改元素樣式的三種方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-08-08詳解一個基于react+webpack的多頁面應(yīng)用配置
這篇文章主要介紹了詳解一個基于react+webpack的多頁面應(yīng)用配置,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-01-01關(guān)于React16.0的componentDidCatch方法解讀
這篇文章主要介紹了關(guān)于React16.0的componentDidCatch方法解讀,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-05-05