单个 Fiber 的 commit 操作
函数声明
function commitWork(fiber: Fiber): void;
根据 Fiber.effectType 的类型进行 commit 操作
函数实现
function commitWork(fiber: Fiber) {
// 向上查找host Fiber类型的parent节点
let parentFiber = fiber.parent;
while (parentFiber.type === "hook") {
parentFiber = parentFiber.parent;
}
// 拿到host Fiber类型的parentFiber的实例(host Fiber类型的实例是真实DOM)
const parentDom = parentFiber.instance;
// 判断effectType
if (fiber.effectType === "place" && fiber.type === "host") {
// 如果是effectType:place,并且当前fiber是host Fiber类型
// 因为组件要被其他组件替换,即UnMount,则执行effects中的清理函数。
commitEffects(fiber);
// place替换真实DOM节点(或append创建)
commitPlace(fiber, parentDom, parentFiber.refChild);
} else if (fiber.effectType === "update") {
// 如果是effectType:update
// diff 新旧fiber的props属性(利用alternate链接到旧的fiber的props)
updateHostProperties(fiber.instance, fiber.alternate.props, fiber.props);
} else if (fiber.effectType === "delete") {
// 如果是effectType:delete
// 组件卸载,执行effects中的清理函数
commitEffects(fiber);
// 删除真实DOM节点
commitDelete(fiber, parentDom);
}
// 如果组件WillMount或者UnMount则执行一次commitEffects
// 本质是遍历Fiber.effects数组,执行注册的副作用任务,并收集副作用的返回值(清理函数)。
if (!fiber.isMount) commitEffects(fiber);
// 如果props中注册了ref指针,并且当前fiber是host Fiber类型,则将实例(真实DOM)赋值给ref.current
if ("ref" in fiber.props && fiber.type === "host") {
fiber.props.ref.current = fiber.instance;
}
}
commitPlace
替换或者创建 host Fiber 的实例
function commitPlace(fiber: Fiber, parentDom: FiberInstance, refChild: Fiber) {
if (refChild) {
// 如果存在refChild表示是一次place操作
const newChild = fiber.instance;
// refChild就是fiber.alternate.sibling.instance,即旧fiber的兄弟节点
const oldChild = refChild.instance;
// 在旧fiber的兄弟节点前插入新fiber的实例
parentDom.insertBefore(newChild, oldChild);
} else {
// 没有refChild,则是一次create操作
// 组件WillMount,设置标志位true
fiber.isMount = true;
// 在DOM树上添加host Fiber实例
parentDom.append(fiber.instance);
}
}
commitDelete
删除 host Fiber 的实例(从 DOM 树上移除)
function commitDelete(fiber: Fiber, parentDom: FiberInstance) {
// 如果是hook Fiber,则找它的host Fiber子节点,但不能是text类型tag
while (fiber.type === "hook") {
if (fiber.child.tag === "text") break;
fiber = fiber.child;
}
// 找到了hook Fiber的host Fiber子节点,将它的实例从DOM树上移除
parentDom.removeChild(fiber.instance);
}