React16源码: React中commitAllHostEffects内部的commitPlacement源码实现
commitPlacement
1 )概述
- 在 react commit 阶段的 commitRoot 第二个while循环中
- 调用了 commitAllHostEffects,在这个函数内部处理了
- 把一个新的dom节点挂载到真正的dom树上面去的一个过程
- 现在主要关注下其中调用的
commitPlacement
2 )源码
定位到 packages/react-reconciler/src/ReactFiberCommitWork.js#L850
function commitPlacement(finishedWork: Fiber): void {
if (!supportsMutation) {
return;
}
// Recursively insert all host nodes into the parent.
const parentFiber = getHostParentFiber(finishedWork);
// Note: these two variables *must* always be updated together.
let parent;
let isContainer;
switch (parentFiber.tag) {
case HostComponent:
parent = parentFiber.stateNode;
isContainer = false;
break;
case HostRoot:
parent = parentFiber.stateNode.containerInfo;
isContainer = true;
break;
case HostPortal:
parent = parentFiber.stateNode.containerInfo;
isContainer = true;
break;
default:
invariant(
false,
'Invalid host parent fiber. This error is likely caused by a bug ' +
'in React. Please file an issue.',
);
}
if (parentFiber.effectTag & ContentReset) {
// Reset the text content of the parent before doing any insertions
resetTextContent(parent);
// Clear ContentReset from the effect tag
parentFiber.effectTag &= ~ContentReset;
}
const before = getHostSibling(finishedWork);
// We only have the top Fiber that was inserted but we need recurse down its
// children to find all the terminal nodes.
let node: Fiber = finishedWork;
while (true) {
if (node.tag === HostComponent || node.tag === HostText) {
if (before) {
if (isContainer) {
insertInContainerBefore(parent, node.stateNode, before);
} else {
insertBefore(parent, node.stateNode, before);
}
} else {
if (isContainer) {
appendChildToContainer(parent, node.stateNode);
} else {
appendChild(parent, node.stateNode);
}
}
} else if (node.tag === HostPortal) {
// If the insertion itself is a portal, then we don't want to traverse
// down its children. Instead, we'll get insertions from each child in
// the portal directly.
} else if (node.child !== null) {
node.child.return = node;
node = node.child;
continue;
}
if (node === finishedWork) {
return;
}
while (node.sibling === null) {
if (node.return === null || node.return === finishedWork) {
return;
}
node = node.return;
}
node.sibling.return = node.return;
node = node.sibling;
}
}
- 进入
getHostParentFiber
function getHostParentFiber(fiber: Fiber): Fiber { let parent = fiber.return; while (parent !== null) { if (isHostParent(parent)) { return parent; } parent = parent.return; } invariant( false, 'Expected to find a host parent. This error is likely caused by a bug ' + 'in React. Please file an issue.', ); } function isHostParent(fiber: Fiber): boolean { return ( fiber.tag === HostComponent || fiber.tag === HostRoot || fiber.tag === HostPortal ); }
- 显然意见,这个循环就是向上查找到第一个
HostComponent
或HostRoot
或HostPortal
- 显然意见,这个循环就是向上查找到第一个
- 之后,判断
parentFiber.tag
,对不同条件的isContainer
进行赋值 - 之后,判断
ContentReset
是否存在,存在则对文本节点进行替换 - 进入
getHostSibling
向上找到 sibling 节点,下面这个英文注释留着 这个是查找sibling的核心算法function getHostSibling(fiber: Fiber): ?Instance { // We're going to search forward into the tree until we find a sibling host // node. Unfortunately, if multiple insertions are done in a row we have to // search past them. This leads to exponential search for the next sibling. // TODO: Find a more efficient way to do this. let node: Fiber = fiber; siblings: while (true) { // If we didn't find anything, let's try the next sibling. while (node.sibling === null) { if (node.return === null || isHostParent(node.return)) { // If we pop out of the root or hit the parent the fiber we are the // last sibling. return null; } node = node.return; } node.sibling.return = node.return; node = node.sibling; // 这个循环要找兄弟节点中的第一个dom节点 // 如果兄弟节点不是 HostComponent 或 HostText 往下去找 // 子节点中的第一个dom节点 while (node.tag !== HostComponent && node.tag !== HostText) { // If it is not host node and, we might have a host node inside it. // Try to search down until we find one. if (node.effectTag & Placement) { // If we don't have a child, try the siblings instead. continue siblings; } // If we don't have a child, try the siblings instead. // We also skip portals because they are not part of this host tree. if (node.child === null || node.tag === HostPortal) { continue siblings; } else { node.child.return = node; node = node.child; } } // Check if this host node is stable or about to be placed. if (!(node.effectTag & Placement)) { // Found it! return node.stateNode; } } }
- 接下去又进入一个while循环
- 里面的第一个判断,
node.tag === HostComponent || node.tag === HostText
- 只有 HostComponent 和 HostText 才有插入dom的需要
- 注意,这里一系列的 if-else 是操作dom的核心
- 里面的第一个判断,
原文地址:https://blog.csdn.net/Tyro_java/article/details/135863654
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!