Appearance
completeWork
由于 render 过程其实属于 DFS(深度优先)过程,因此第一个触发 completeWork的顺序是子节点到父节点
js
function completeWork(current, workInProgress) {
//...
switch (workInProgress.tag) {
// 子节点(可能是文本节点,也可能是html节点或其他)
// ...
case HostComponent: // html
// 首屏渲染逻辑
// 1. 创建 dom 节点
const instance = createInstance(type, newProps, rootContainerInstance, currentHostContext, workInProgress);
// 2. 挂载 workInProgress 的 子节点
appendAllChildren(instance, workInProgress, false, false);
// 3. 首屏渲染的dom节点赋值到 workInProgress(当前FiberNode)的 stateNode
workInProgress.stateNode = instance;
if (finalizeInitialChildren(instance, type, newProps, rootContainerInstance)) {
markUpdate(workInProgress);
}
}
}
createInstance
负责创建dom节点
js
function createInstance(type, props, rootInstance) {
// ... domElemenet 就是通过 document.createElement 生成的 dom 节点
const domElement: Instance = createElement(type, props, rootContainerInstance, parentNamespace);
return domElement // 返回给上层使用
}
appendAllChildren
负责挂载 workInProgress 的子节点
js
appendAllChildren = function (parent, workInProgress) {
let node = workInProgress.child;
// 循环将子节点列表的 dom 全部挂载
while (node !== null) {
if (node.tag === HostComponent || node.tag === HostText) {
appendInitialChild(parent, node.stateNode);
} else if (node.tag === HostPortal) ; else if (node.child !== null) {
//...
}
if (node === workInProgress) {
return;
}
while (node.sibling === null) {
if (node.return === null || node.return === workInProgress) {
return;
}
node = node.return;
}
node.sibling.return = node.return;
node = node.sibling;
}
};
如何挂载到页面上
FiberRootNode
在 reconcileChildren
的 分支过程中(参考2-1),会在 placeSingleChild
赋值 App
节点 flags = Placement(2)
js
function placeSingleChild(newFiber) {
// 首屏渲染,App FiberNode没有alternate,因此 flags 标记 Placement
if (shouldTrackSideEffects && newFiber.alternate === null) {
newFiber.flags |= Placement;
}
return newFiber;
}
function performSyncWorkOnRoot() {
// ...
// finishedWork 本次更新生成的 FiberNode 树,里面包含完整的 DOM 树
const finishedWork = root.current.alternate;
root.finishedWork = finishedWork;
root.finishedLanes = lanes;
// commit 挂载 DOM 到页面
commitRoot(root);
}