updateContainer做了什么?
当react创建好RootFiber后,然后会调用updateContainer将应用渲染出来, 首先,计算expirationTime, 然后调用updateContainerAtExpirationTime 方法
typescript
export function updateContainer(
element: ReactNodeList,
container: OpaqueRoot,
parentComponent: ?React$Component<any, any>,
callback: ?Function,
): ExpirationTime {
// root fiber
const current = container.current;
const currentTime = requestCurrentTime();
// 计算expirationTime
const expirationTime = computeExpirationForFiber(currentTime, current);
return updateContainerAtExpirationTime(
element,
container,
parentComponent,
expirationTime,
callback,
);
}updateContainerAtExpirationTime方法创建了context相关的对象,然后直接执行scheduleRootUpdate
scheduleRootUpdate
scheduleRootUpdate方法从RootFiber开始进行调度,主要做了3件事
- 创建update, 当前update要更新的其实是ReactDOM.render的第一个参数,正常情况下是我们的 组件
- 将update添加到当前Fiber(RootFiber)的updateQueue上面
- 执行scheduleWork方法
typescript
function scheduleRootUpdate(
current: Fiber,
element: ReactNodeList,
expirationTime: ExpirationTime,
callback: ?Function,
) {
const update = createUpdate(expirationTime);
update.payload = {element};
// 在一开始render的时候
// 将当前组件的Element放在Fiber的updateQueue上
enqueueUpdate(current, update);
scheduleWork(current, expirationTime);
return expirationTime;
}createUpdate
react产生的更新,都是调用此方法创建的
typescript
export function createUpdate(expirationTime: ExpirationTime): Update<*> {
return {
expirationTime: expirationTime,
tag: UpdateState,
payload: null,
callback: null,
next: null,
nextEffect: null,
};
}enqueueUpdate
enqueueUpdate是将当前update添加到队列里,此队列是一个单向链表, 具体的代码实现如下, 具体做了两件事:
- 确保updateQueue被创建
- 将update插入的链表尾部
typescript
export function enqueueUpdate<State>(fiber: Fiber, update: Update<State>) {
// alternate 是更新中的那个fiber对象,更新完会跟Fiber交换位置
// 也是Fiber架构双缓冲技术实现的关键
const alternate = fiber.alternate;
let queue1;
let queue2;
if (alternate === null) {
// 如果alternate为空,说明是第一次渲染
queue1 = fiber.updateQueue;
queue2 = null;
if (queue1 === null) {
// 如果queue1是null, 则首先创建queue1
queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState);
}
} else {
// 说明不是第一次渲染,alternate在上一次渲染的时候已经创建了
queue1 = fiber.updateQueue;
queue2 = alternate.updateQueue;
if (queue1 === null) {
if (queue2 === null) {
// 说明当前fiber还没有过更新,则创建queue1和queue2
queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState);
queue2 = alternate.updateQueue = createUpdateQueue(
alternate.memoizedState,
);
} else {
// 如果queue1不存在,但是queue2存在,那就把queue复制一份
// 这种情况的出现可能是第第二次渲染后,产生了多个更新的情况
// 第一次渲染没产生更新,但是第二次产生了多个更新
queue1 = fiber.updateQueue = cloneUpdateQueue(queue2);
}
} else {
if (queue2 === null) {
// 如果queue1存在,但是queue2不存在,那就复制一份
queue2 = alternate.updateQueue = cloneUpdateQueue(queue1);
} else {
// Both owners have an update queue.
}
}
}
// 上面的代码其实就是初始化queue1和queue2
// 下面的才是真正的update加入的updateQueue
if (queue2 === null || queue1 === queue2) {
// 如果queue2不存在 或者两者相等,直接将update添加到队列中
appendUpdateToQueue(queue1, update);
} else {
if (queue1.lastUpdate === null || queue2.lastUpdate === null) {
// 其中一个队列是空的 ,都需要添加
appendUpdateToQueue(queue1, update);
appendUpdateToQueue(queue2, update);
} else {
//两个队列都不是空的。上一次更新在两个列表中都是相同的,
//因为结构共享。所以,只需附加到其中一个列表。
appendUpdateToQueue(queue1, update);
// 更新一下queue2的指针
queue2.lastUpdate = update;
}
}
}注意
alternate是react Fiber架构下的缓存技术,在更新完后,会将alternate对应的Fiber和当前老的 Fiber交换位置, 具体的说明带扩展 TODO