1 )概述
2 )种类
3 ) 源码
updateContainer
中
computeExpirationForFiber
function computeExpirationForFiber(currentTime: ExpirationTime, fiber: Fiber) {
let expirationTime;
if (expirationContext !== NoWork) {
// An explicit expiration context was set;
expirationTime = expirationContext;
} else if (isWorking) {
if (isCommitting) {
// Updates that occur during the commit phase should have sync priority
// by default.
expirationTime = Sync;
} else {
// Updates during the render phase should expire at the same time as
// the work that is being rendered.
expirationTime = nextRenderExpirationTime;
}
} else {
// No explicit expiration context was set, and we're not currently
// performing work. Calculate a new expiration time.
if (fiber.mode & ConcurrentMode) {
if (isBatchingInteractiveUpdates) {
// This is an interactive update
expirationTime = computeInteractiveExpiration(currentTime);
} else {
// This is an async update
expirationTime = computeAsyncExpiration(currentTime);
}
// If we're in the middle of rendering a tree, do not update at the same
// expiration time that is already rendering.
if (nextRoot !== null && expirationTime === nextRenderExpirationTime) {
expirationTime += 1;
}
} else {
// This is a sync update
expirationTime = Sync;
}
}
if (isBatchingInteractiveUpdates) {
// This is an interactive update. Keep track of the lowest pending
// interactive expiration time. This allows us to synchronously flush
// all interactive updates when needed.
if (expirationTime > lowestPriorityPendingInteractiveExpirationTime) {
lowestPriorityPendingInteractiveExpirationTime = expirationTime;
}
}
return expirationTime;
}
expirationContext
的判断
ExpirationTime
类型,默认初始化值是 NoWork
function deferredUpdates<A>(fn: () => A): A {
const currentTime = requestCurrentTime();
const previousExpirationContext = expirationContext;
const previousIsBatchingInteractiveUpdates = isBatchingInteractiveUpdates;
expirationContext = computeAsyncExpiration(currentTime); // 这里
isBatchingInteractiveUpdates = false;
try {
return fn();
} finally {
expirationContext = previousExpirationContext;
isBatchingInteractiveUpdates = previousIsBatchingInteractiveUpdates;
}
}
expirationContext = computeAsyncExpiration(currentTime);
computeAsyncExpiration
这个函数对其进行修改赋值function syncUpdates<A, B, C0, D, R>(
fn: (A, B, C0, D) => R,
a: A,
b: B,
c: C0,
d: D,
): R {
const previousExpirationContext = expirationContext;
expirationContext = Sync; // 变成了 Sync
try {
return fn(a, b, c, d); // 这里是 setState 操作
} finally {
expirationContext = previousExpirationContext; // 最终还原
}
}
syncUpdates
在 ReactDOM.js 中的 flushSync
API
flushSync: DOMRenderer.flushSync
一直溯源往上找到 ReactFiberScheduler.js 中的 flushSync
flushSync
// TODO: Batching should be implemented at the renderer level, not within
// the reconciler.
function flushSync<A, R>(fn: (a: A) => R, a: A): R {
invariant(
!isRendering,
'flushSync was called from inside a lifecycle method. It cannot be ' +
'called when React is already rendering.',
);
const previousIsBatchingUpdates = isBatchingUpdates;
isBatchingUpdates = true;
try {
return syncUpdates(fn, a); // 这里
} finally {
isBatchingUpdates = previousIsBatchingUpdates;
performSyncWork();
}
}
syncUpdates
,在之前的示例中,如下flushSync(() => {
this.setState({
num: newNum,
})
})
expirationTime
变成了 Sync
expirationContext
进行赋值expirationTime
变成了 Sync
就不符合第一种情况了,这时候往下走,匹配到了 isWorking
isWorking
表示有任务正在更新if (fiber.mode & ConcurrentMode)
fiber.mode
是否是 ConcurrentMode
ConcurrentMode
的定义处 ReactTypeOfMode.jsexport type TypeOfMode = number;
export const NoContext = 0b000;
export const ConcurrentMode = 0b001;
export const StrictMode = 0b010;
export const ProfileMode = 0b100;
const a = 0b000;
const b = 0b001;
const c = 0b010;
const d = 0b100;
let mode = a; // 默认等于 a, 在后续渲染时并不知道是否有更改过
mode & b // 如果 结果为 0 表示没有过b这种情况
mode |= b // 这样给 mode 增加 b,这时候 mode 变成1,就对应了 b
mode |= c // 给 mode 增加 c, 这时候 mode 变成 3,也就是 0b011
mode & b // 这时候判断mode是否有b, 如果是1,则有b, 结果是1 对应b
mode & c // 这时候判断mode是否有c, 如果是1,则有c, 结果是2 对应c
computeInteractiveExpiration
和 computeAsyncExpiration
两个函数中的一个计算 expirationTime
if (isBatchingInteractiveUpdates) {
// This is an interactive update
expirationTime = computeInteractiveExpiration(currentTime);
} else {
// This is an async update
expirationTime = computeAsyncExpiration(currentTime);
}
isBatchingInteractiveUpdates
在 interactiveUpdates
函数中被赋值为 true
interactiveUpdates
情况下,也就是 isBatchingInteractiveUpdates
为 true 时expirationTime += 1;
是为了区分下一个即将进行的更新和当前正在创造的更新,防止一样,强制把当前+1Sync