引言本文对应的 react 版本是 18 2 0
下面的 dom 结构react 内部是如何遍历的
const App = () => {return (
引言
本文对应的 react 版本是 18.2.0
下面的 dom 结构react 内部是如何遍历的
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 内部遍历核心逻辑:
- 在
render时调用commitPassiveUnmountOnFiber函数 commitPassiveUnmountOnFiber处理不同的WorkTag,并调用recursivelyTraversePassiveUnmountEffectsrecursivelyTraversePassiveUnmountEffects根据当前Fiber的子节点有没有passive effect(useEffect,useLayoutEffect)来决定是否遍历当前Fiber的子节点- 如果子节点有
passive effect,则优先遍历子节点 (深度优先),直到找到最终的叶子节点,退出当前循环 - 然后进入兄弟节点,开始遍历兄弟节点的子节点
- 具体从哪个兄弟节点开始遍历,
react选择的是离退出循环的那个叶子节点的父节点,检查有没有子节点,以此循环遍历
- 具体从哪个兄弟节点开始遍历,
- 直到最后找到所有有
passive effect的节点
- 如果子节点有
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组件中节点是<div>,<di >的tag是5<div>下面有两个子元素<button>、<A>
- 先遍历
<button>它的tag是5 <button>内部只有一个文本节点,没有passive effect- 所以
react不遍历了(跳出当前遍历的循环,也就是button这条不在遍历了)
- 所以
- 跳出循环后,查看
button的兄弟节点,它的兄弟节点是<A>,<A>的tag是0 - 由于
<A>节点的子节点没有passive effect,所以跳出循环,结束整个遍历
总结
- 从跟节点开始遍历
- 当前组件的子组件有没有
passive effect - 采取深度优先
- 如果
dom节点内有函数组件,则这个dom会被遍历,否则不会遍历 - 如果当前
fiber下的所有子fiber都没有passive effect,则这一整个都链表都不会被遍历 - 如果当前
fiber只有dom,则这些dom也不会遍历
总的来说组件会不会别遍历看 fiber 有没有 passive effect:
- 有,一定会被遍历
- 没有,下面两种情况会被遍历,其他情况不会被遍历
- 是
passive effect的父组件 - 和
passive effect组件是兄弟组件
- 是
passive effect 指的是 useEffect,useLayoutEffect
遍历逻辑如下图所示
图中画绿色勾的都会被遍历,红色勾是遍历的顺序

以上就是一文掌握React 组件树遍历技巧的详细内容,更多关于React 组件树遍历的资料请关注好代码网其它相关文章!