-
Notifications
You must be signed in to change notification settings - Fork 414
Open
Description
在源码的实现中,删除一个fiber节点的副作用处理,是通过循环模拟递归过程,使用 rootChildrenToDelete这个全局状态维护需要删除的host节点列表,同时使用recordHostChildrenToDelete做了同层sibling才添加到rootChildrenToDelete的限制,这在host节点都处在同一层时有效,但是场景扩展到在一棵将被删除的子树中,首层host节点分布在不同深度时,这个逻辑就不适用了。建议还是采用react源码实现中函数递归的形式处理删除副作用,这样可以在方便做host节点查找的截断的同时,不影响到host节点下子孙节点的卸载副作用处理
<Body> // to delete
<div>first</div>
<Content>
<p>second<p/>
</Content>
</Body>function recordHostChildrenToDelete(
childrenToDelete: FiberNode[],
unmountFiber: FiberNode
) {
// 1. 找到第一个root host节点
const lastOne = childrenToDelete[childrenToDelete.length - 1];
if (!lastOne) {
childrenToDelete.push(unmountFiber);
} else {
let node = lastOne.sibling;
while (node !== null) {
if (unmountFiber === node) {
childrenToDelete.push(unmountFiber);
}
node = node.sibling;
}
}
// 2. 每找到一个 host节点,判断下这个节点是不是 1 找到那个节点的兄弟节点
}
function commitDeletion(childToDelete: FiberNode, root: FiberRootNode) {
const rootChildrenToDelete: FiberNode[] = [];
// 递归子树
commitNestedComponent(childToDelete, (unmountFiber) => {
switch (unmountFiber.tag) {
case HostComponent:
recordHostChildrenToDelete(rootChildrenToDelete, unmountFiber);
safelyDetachRef(unmountFiber);
return;
case HostText:
recordHostChildrenToDelete(rootChildrenToDelete, unmountFiber);
return;
case FunctionComponent:
commitPassiveEffect(unmountFiber, root, 'unmount');
return;
default:
if (__DEV__) {
console.warn('未处理的unmount类型', unmountFiber);
}
}
});
// 移除rootHostComponent的DOM
if (rootChildrenToDelete.length) {
const hostParent = getHostParent(childToDelete);
if (hostParent !== null) {
rootChildrenToDelete.forEach((node) => {
removeChild(node.stateNode, hostParent);
});
}
}
childToDelete.return = null;
childToDelete.child = null;
}
function commitNestedComponent(
root: FiberNode,
onCommitUnmount: (fiber: FiberNode) => void
) {
let node = root;
while (true) {
onCommitUnmount(node);
if (node.child !== null) {
// 向下遍历
node.child.return = node;
node = node.child;
continue;
}
if (node === root) {
// 终止条件
return;
}
while (node.sibling === null) {
if (node.return === null || node.return === root) {
return;
}
// 向上归
node = node.return;
}
node.sibling.return = node.return;
node = node.sibling;
}
}Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels