一文掌握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)用recursivelyTraversePassiveUnmountEffectsrecursivelyTraversePassiveUnmountEffects根據(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 組件樹遍歷技巧的詳細(xì)內(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

