引言
本文对应的 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 ,并调用 recursivelyTraversePassiveUnmountEffects recursivelyTraversePassiveUnmountEffects 根据当前 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 组件树遍历的资料请关注其它相关文章!
原文地址:https://juejin.cn/post/7221479555496017980
查看更多关于一文掌握React 组件树遍历技巧的详细内容...
声明:本文来自网络,不代表【好得很程序员自学网】立场,转载请注明出处:http://www.haodehen.cn/did222232