reconcile 阶段入口
判断当前 fiber 的类型(host or hook),如果是 host 类型则根据 fiber.tag 生成一个 dom 节点,如果是 hook 类型则实例就是自己,在实例上保存一个 stateNode 属性(还是自己)用于在 createWorkInProgress 执行中回溯到 rootFiber。
function beginWork(fiber: Fiber) {
if (fiber.type === "hook") {
return updateHOOKComponent(fiber);
} else {
return updateHostComponent(fiber);
}
}
updateHostComponent
更新 host Fiber
function updateHostComponent(fiber: Fiber) {
// 如果实例不存在,则生成一个真实DOM节点赋给instance
if (!fiber.instance) fiber.instance = renderToDOM(fiber);
// 对props.children(通过React.createElement生成的VNode树的children集合)进行reconcile新旧比对,标记effectType
return reconcileChildren(fiber, fiber.props.children);
}
renderToDOM
根据 host Fiber 生成对应实例(真实 DOM)
function renderToDOM(fiber: Fiber) {
// 如果fiber.tag是function类型,则返回(这里主要用于类型安全)
if (typeof fiber.tag === "function") return;
// host Fiber实例可能是Element也可能是Text
let dom: HTMLElement | Text = null;
if (fiber.tag === "text") {
// 如果tag 值为 text,则创建一个文本节点
dom = document.createTextNode("");
} else {
// 根据fiber.tag创建对应真实DOM
dom = document.createElement(fiber.tag);
}
// 根据fiber.props(即JSX标签上的属性)更新DOM节点
// 第二个参数为oldProps,因为这是Fiber实例初始化,故没有alternate(旧的Fiber)。直接传一个空属性进去。
updateHostProperties(dom, {}, fiber.props);
return dom as FiberInstance;
}
updateHOOKComponent
更新 hook Fiber
function updateHOOKComponent(fiber: Fiber) {
// 如果实例不存在,则把函数组件对应Fiber(就是自己)赋给instance
if (!fiber.instance) fiber.instance = fiber as FiberInstance;
// 在实例上保存一个 stateNode 属性(还是自己)用于回溯到 rootFiber。
fiber.instance.stateNode = fiber;
// 给全局变量currentFiber赋值,在Hook API使用
currentFiber = fiber.instance;
// 用于hook API ID 分配,hook需要一个id来标识
// 例如函数组件内多个useState Hook,在fiber.state上保存initialState时需要利用id区分
// Order.fallback在hook组件执行后将id分配器回滚。(具体见后续实现)
Order.fallback();
// 这里判断fiber.tag是否为function类型,hook Fiber的实例是函数组件,所以tag就是函数组件。
if (typeof fiber.tag !== "function") return;
// 执行函数组件,并传入props对象,返回hook Fiber的 Vnode children
return reconcileChildren(fiber, fiber.tag(fiber.props));
}