Skip to content

Commit b04c7fa

Browse files
committed
Decouple expiration times and transition timeouts (#17920)
We currently use the expiration time to represent the timeout of a transition. Since we intend to stop treating work priority as a timeline, we can no longer use this trick. In this commit, I've changed it to store the event time on the update object instead. Long term, we will store event time on the root as a map of transition -> event time. I'm only storing it on the update object as a temporary workaround to unblock the rest of the changes.
1 parent dc630d3 commit b04c7fa

11 files changed

+136
-145
lines changed

packages/react-reconciler/src/ReactFiberClassComponent.new.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ const classComponentUpdater = {
196196
suspenseConfig,
197197
);
198198

199-
const update = createUpdate(expirationTime, suspenseConfig);
199+
const update = createUpdate(currentTime, expirationTime, suspenseConfig);
200200
update.payload = payload;
201201
if (callback !== undefined && callback !== null) {
202202
if (__DEV__) {
@@ -218,7 +218,7 @@ const classComponentUpdater = {
218218
suspenseConfig,
219219
);
220220

221-
const update = createUpdate(expirationTime, suspenseConfig);
221+
const update = createUpdate(currentTime, expirationTime, suspenseConfig);
222222
update.tag = ReplaceState;
223223
update.payload = payload;
224224

@@ -242,7 +242,7 @@ const classComponentUpdater = {
242242
suspenseConfig,
243243
);
244244

245-
const update = createUpdate(expirationTime, suspenseConfig);
245+
const update = createUpdate(currentTime, expirationTime, suspenseConfig);
246246
update.tag = ForceUpdate;
247247

248248
if (callback !== undefined && callback !== null) {

packages/react-reconciler/src/ReactFiberExpirationTime.new.js

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ export const Idle = 2;
3535
// Continuous Hydration is slightly higher than Idle and is used to increase
3636
// priority of hover targets.
3737
export const ContinuousHydration = 3;
38+
export const LongTransition = 49999;
39+
export const ShortTransition = 99999;
3840
export const Sync = MAX_SIGNED_31_BIT_INT;
3941
export const Batched = Sync - 1;
4042

@@ -84,16 +86,13 @@ export function computeAsyncExpiration(
8486
);
8587
}
8688

87-
export function computeSuspenseExpiration(
89+
export function computeSuspenseTimeout(
8890
currentTime: ExpirationTime,
8991
timeoutMs: number,
9092
): ExpirationTime {
91-
// TODO: Should we warn if timeoutMs is lower than the normal pri expiration time?
92-
return computeExpirationBucket(
93-
currentTime,
94-
timeoutMs,
95-
LOW_PRIORITY_BATCH_SIZE,
96-
);
93+
const currentTimeMs = expirationTimeToMs(currentTime);
94+
const deadlineMs = currentTimeMs + timeoutMs;
95+
return msToExpirationTime(deadlineMs);
9796
}
9897

9998
// We intentionally set a higher expiration time for interactive updates in

packages/react-reconciler/src/ReactFiberHooks.new.js

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,9 @@ import {getIsRendering} from './ReactCurrentFiber';
9696
const {ReactCurrentDispatcher, ReactCurrentBatchConfig} = ReactSharedInternals;
9797

9898
type Update<S, A> = {|
99+
// TODO: Temporary field. Will remove this by storing a map of
100+
// transition -> start time on the root.
101+
eventTime: ExpirationTime,
99102
expirationTime: ExpirationTime,
100103
suspenseConfig: null | SuspenseConfig,
101104
action: A,
@@ -715,14 +718,17 @@ function updateReducer<S, I, A>(
715718
let newBaseQueueLast = null;
716719
let update = first;
717720
do {
721+
const suspenseConfig = update.suspenseConfig;
718722
const updateExpirationTime = update.expirationTime;
723+
const updateEventTime = update.eventTime;
719724
if (updateExpirationTime < renderExpirationTime) {
720725
// Priority is insufficient. Skip this update. If this is the first
721726
// skipped update, the previous update/state is the new base
722727
// update/state.
723728
const clone: Update<S, A> = {
724-
expirationTime: update.expirationTime,
725-
suspenseConfig: update.suspenseConfig,
729+
eventTime: updateEventTime,
730+
expirationTime: updateExpirationTime,
731+
suspenseConfig: suspenseConfig,
726732
action: update.action,
727733
eagerReducer: update.eagerReducer,
728734
eagerState: update.eagerState,
@@ -744,6 +750,7 @@ function updateReducer<S, I, A>(
744750

745751
if (newBaseQueueLast !== null) {
746752
const clone: Update<S, A> = {
753+
eventTime: updateEventTime,
747754
expirationTime: Sync, // This update is going to be committed so we never want uncommit it.
748755
suspenseConfig: update.suspenseConfig,
749756
action: update.action,
@@ -760,10 +767,7 @@ function updateReducer<S, I, A>(
760767
// TODO: We should skip this update if it was already committed but currently
761768
// we have no way of detecting the difference between a committed and suspended
762769
// update here.
763-
markRenderEventTimeAndConfig(
764-
updateExpirationTime,
765-
update.suspenseConfig,
766-
);
770+
markRenderEventTimeAndConfig(updateEventTime, suspenseConfig);
767771

768772
// Process this update.
769773
if (update.eagerReducer === reducer) {
@@ -1651,6 +1655,7 @@ function dispatchAction<S, A>(
16511655
);
16521656

16531657
const update: Update<S, A> = {
1658+
eventTime: currentTime,
16541659
expirationTime,
16551660
suspenseConfig,
16561661
action,

packages/react-reconciler/src/ReactFiberNewContext.new.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ export function propagateContextChange(
206206

207207
if (fiber.tag === ClassComponent) {
208208
// Schedule a force update on the work-in-progress.
209-
const update = createUpdate(renderExpirationTime, null);
209+
const update = createUpdate(NoWork, renderExpirationTime, null);
210210
update.tag = ForceUpdate;
211211
// TODO: Because we don't have a work-in-progress, this will add the
212212
// update to the current fiber, too, which means it will persist even if

packages/react-reconciler/src/ReactFiberReconciler.new.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ export function updateContainer(
271271
}
272272
}
273273

274-
const update = createUpdate(expirationTime, suspenseConfig);
274+
const update = createUpdate(currentTime, expirationTime, suspenseConfig);
275275
// Caution: React DevTools currently depends on this property
276276
// being called "element".
277277
update.payload = {element};

packages/react-reconciler/src/ReactFiberThrow.new.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ import {
5656
} from './ReactFiberWorkLoop.new';
5757
import {logCapturedError} from './ReactFiberErrorLogger';
5858

59-
import {Sync} from './ReactFiberExpirationTime.new';
59+
import {Sync, NoWork} from './ReactFiberExpirationTime.new';
6060

6161
const PossiblyWeakMap = typeof WeakMap === 'function' ? WeakMap : Map;
6262

@@ -65,7 +65,7 @@ function createRootErrorUpdate(
6565
errorInfo: CapturedValue<mixed>,
6666
expirationTime: ExpirationTime,
6767
): Update<mixed> {
68-
const update = createUpdate(expirationTime, null);
68+
const update = createUpdate(NoWork, expirationTime, null);
6969
// Unmount the root by rendering null.
7070
update.tag = CaptureUpdate;
7171
// Caution: React DevTools currently depends on this property
@@ -84,7 +84,7 @@ function createClassErrorUpdate(
8484
errorInfo: CapturedValue<mixed>,
8585
expirationTime: ExpirationTime,
8686
): Update<mixed> {
87-
const update = createUpdate(expirationTime, null);
87+
const update = createUpdate(NoWork, expirationTime, null);
8888
update.tag = CaptureUpdate;
8989
const getDerivedStateFromError = fiber.type.getDerivedStateFromError;
9090
if (typeof getDerivedStateFromError === 'function') {
@@ -260,7 +260,7 @@ function throwException(
260260
// When we try rendering again, we should not reuse the current fiber,
261261
// since it's known to be in an inconsistent state. Use a force update to
262262
// prevent a bail out.
263-
const update = createUpdate(Sync, null);
263+
const update = createUpdate(NoWork, Sync, null);
264264
update.tag = ForceUpdate;
265265
enqueueUpdate(sourceFiber, update);
266266
}

0 commit comments

Comments
 (0)