1、逻辑分层
- scheduleUpdateOnFiber方法为调度更新
- performSyncWorkOnRoot为开启render阶段(render阶段)
commitRoot为真实Dom渲染过程(commit阶段)
ReactDOM.render可以我分为三个阶段:
初始化主要干的事就是完成 Fiber 树中基本实体的创建,具体请移步查看源码阅读篇。
八、render阶段
2.1 主体逻辑链路
主要逻辑代码如下:
function legacyRenderSubtreeIntoContainer(parentComponent, children, container, forceHydrate, callback) {
// container 对应的是我们传入的真实 DOM 对象
var root = container._reactRootContainer;
// 初始化 fiberRoot 对象
var fiberRoot;
// DOM 对象本身不存在 _reactRootContainer 属性,因此 root 为空
if (!root) {
// 若 root 为空,则初始化 _reactRootContainer,并将其值赋值给 root
root = container._reactRootContainer = legacyCreateRootFromDOMContainer(container, forceHydrate);
// legacyCreateRootFromDOMContainer 创建出的对象会有一个 _internalRoot 属性,将其赋值给 fiberRoot
fiberRoot = root._internalRoot;
// 这里处理的是 ReactDOM.render 入参中的回调函数,你了解即可
if (typeof callback === 'function') {
// ...省略
}
// 进入 unbatchedUpdates 方法
unbatchedUpdates(function () {
updateContainer(children, fiberRoot, parentComponent, callback);
});
} else {
// ...省略
updateContainer(children, fiberRoot, parentComponent, callback);
}
return getPublicRootInstance(fiberRoot);
}
上面代码主要逻辑链路:
2.2 root拆解:
这段代码其实就是做了这件事:
- 创建 FiberRoot 和 rootFiber
- fiberRoot的current属性指向rootFiber,
- rootFiber的stateNode属性执行fiberRoot
fiberRoot 的关联对象是真实 DOM 的容器节点;而 rootFiber 则作为虚拟 DOM 的根节点存在。这两个节点,将是后续整棵 Fiber 树构建的起点。
2.3 unbatchedUpdates方法拆解:
unbatchedUpdates(function () {
updateContainer(children, fiberRoot, parentComponent, callback);
});
unbatchedUpdates方法:
function unbatchedUpdates(fn, a) {
// ...省略...
try {
// 重点在这里,直接调用了传入的回调函数 fn,对应当前链路中的 updateContainer 方法
return fn(a);
} finally {
// ...省略...
}
}
updateContainer方法:
function updateContainer(element, container, parentComponent, callback) {
......
// 这是一个 event 相关的入参,此处不必关注
var eventTime = requestEventTime();
......
// 这是一个比较关键的入参,lane 表示优先级
var lane = requestUpdateLane(current$1);
// 结合 lane(优先级)信息,创建 update 对象,一个 update 对象意味着一个更新
var update = createUpdate(eventTime, lane);
// update 的 payload 对应的是一个 React 元素
update.payload = {
element: element
};
// 处理 callback,这个 callback 其实就是我们调用 ReactDOM.render 时传入的 callback
callback = callback === undefined ? null : callback;
if (callback !== null) {
{
if (typeof callback !== 'function') {
error('render(...): Expected the last optional `callback` argument to be a ' + 'function. Instead received: %s.', callback);
}
}
update.callback = callback;
}
// 将 update 入队
enqueueUpdate(current$1, update);
// 调度 fiberRoot
scheduleUpdateOnFiber(current$1, lane, eventTime);
// 返回当前节点(fiberRoot)的优先级
return lane;
}
updateContainer最关键的事情可以总结为三件:
ReactDOM.render(
- blocking 模式:
ReactDOM.createBlockingRoot(rootNode).render(
- concurrent 模式:
ReactDOM.createRoot(rootNode).render(
我们目前常用的 ReactDOM.render 对应的是 legacy 模式,它实际触发的仍然是同步的渲染链路。
同步的 ReactDOM.render,异步的ReactDOM.createRoot。