本文小编为大家详细介绍“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进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。