ReactRoot.prototype.render
上文是创建了root节点,这一篇是创建之后发生的事情
// batchedUpdate 是 React 中很重要的一步,也就是批量更新
// this.setState({ age: 1 })
// this.setState({ age: 2 })
// this.setState({ age: 3 })
// 以上三次 setState 会被优化成一次更新,减少了渲染次数
// 但是对于 Root 来说没必要批量更新,直接调用回调函数
unbatchedUpdates(() => {
// 上文中传入的parentComponent为null,所以直接进入render
// 其实也不是没可能存在 parentComponent,如果在 root 上使用 context 就可以了
if (parentComponent != null) {
root.legacy_renderSubtreeIntoContainer(
parentComponent,
children,
callback,
);
} else {
// 调用的是 ReactRoot.prototype.render
root.render(children, callback);
}
});
ReactRoot.prototype.render = function(
children: ReactNodeList,
callback: ?() => mixed,
): Work {
// 这里指 FiberRoot
const root = this._internalRoot;
// ReactWork 的功能就是为了在组件渲染或更新后把所有传入
// ReactDom.render 中的回调函数全部执行一遍
const work = new ReactWork();
callback = callback === undefined ? null : callback;
// 如果有 callback,就 push 进 work 中的数组
if (callback !== null) {
work.then(callback);
}
// work._onCommit 就是用于执行所有回调函数的
updateContainer(children, root, null, work._onCommit);
return work;
};
updateContainer
我们先从 FiberRoot 的 current 属性中取出它的 fiber 对象,然后计算了两个时间。这两个时间在 React 中相当重要。 只需要记住任务的过期时间是通过当前时间加上一个常量(任务优先级不同常量不同)计算出来的
function updateContainer(
element: ReactNodeList,
container: OpaqueRoot,
parentComponent: ?React$Component<any, any>,
callback: ?Function,
): ExpirationTime {
// 取出容器的 fiber 对象,也就是 fiber root
const current = container.current;
// 计算时间
const currentTime = requestCurrentTime();
// expirationTime 代表优先级,数字越大优先级越高
// sync 的数字是最大的,所以优先级也是最高的
const expirationTime = computeExpirationForFiber(currentTime, current);
// updateContainerAtExpirationTime这个函数直接返回scheduleRootUpdate,所以直接看它
return updateContainerAtExpirationTime(
element,
container,
parentComponent,
expirationTime,
callback,
);
}
scheduleRootUpdate
function scheduleRootUpdate(
current: Fiber,
element: ReactNodeList,
expirationTime: ExpirationTime,
callback: ?Function,
) {
// 创建一个 update,就是内部有几个属性的对象
const update = createUpdate(expirationTime);
// 第一次render直接将element当做payload
// being called "element".
update.payload = {element};
callback = callback === undefined ? null : callback;
if (callback !== null) {
update.callback = callback;
}
// 把 update 入队,内部就是一些创建或者获取 queue(链表结构),然后给链表添加一个节点的操作
enqueueUpdate(current, update);
// 调度相关
scheduleWork(current, expirationTime);
return expirationTime;
}
createUpdate
这个方法返回的对象和setState有关
function createUpdate(expirationTime: ExpirationTime): Update<*> {
return {
expirationTime: expirationTime,
tag: UpdateState,
// setState 的第一二个参数
payload: null,
callback: null,
// 用于在队列中找到下一个节点
next: null,
nextEffect: null,
};
}
render的整体流程