Skip to content

Commit 68817d9

Browse files
lunaruanrickhanlonii
authored andcommitted
[Transition Tracing] Add transition to OffscreenState and pendingSuspenseBoundaries to RootState (#24340)
In this PR we: Add transitions boilerplate to the OffscreenState. The transitions field will be null on initiation. During the commit phase, if there are any new transitions, we will add any new transitions (either as a result of a transition occurring or a parent suspense boundary completing) to the transitions field. Once the suspense boundary resolves, we no longer need to store the transitions on the boundary, so we can put this field on the Offscreen memoized state Add pendingSuspenseBoundaries boilerplate to the RootState. This field starts as null. During the commit phase, if a suspense boundary has either gone from fallback to resolved or from resolved to fallback, we will create a new Map if there isn't one, and if there is, we will add (if the boundary is a fallback) or remove the suspense boundary (if the boundary has resolved) from the map. Add an optional name field to the Suspense boundary
1 parent 239d347 commit 68817d9

11 files changed

+46
-45
lines changed

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

+7-11
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,6 @@ import {
236236
markSkippedUpdateLanes,
237237
getWorkInProgressRoot,
238238
pushRenderLanes,
239-
getWorkInProgressTransitions,
240239
} from './ReactFiberWorkLoop.new';
241240
import {setWorkInProgressVersion} from './ReactMutableSource.new';
242241
import {pushCacheProvider, CacheContext} from './ReactFiberCacheComponent.new';
@@ -652,9 +651,11 @@ function updateOffscreenComponent(
652651
// Rendering a hidden tree.
653652
if ((workInProgress.mode & ConcurrentMode) === NoMode) {
654653
// In legacy sync mode, don't defer the subtree. Render it now.
654+
// TODO: Consider how Offscreen should work with transitions in the future
655655
const nextState: OffscreenState = {
656656
baseLanes: NoLanes,
657657
cachePool: null,
658+
transitions: null,
658659
};
659660
workInProgress.memoizedState = nextState;
660661
if (enableCache) {
@@ -688,6 +689,7 @@ function updateOffscreenComponent(
688689
const nextState: OffscreenState = {
689690
baseLanes: nextBaseLanes,
690691
cachePool: spawnedCachePool,
692+
transitions: null,
691693
};
692694
workInProgress.memoizedState = nextState;
693695
workInProgress.updateQueue = null;
@@ -723,6 +725,7 @@ function updateOffscreenComponent(
723725
const nextState: OffscreenState = {
724726
baseLanes: NoLanes,
725727
cachePool: null,
728+
transitions: null,
726729
};
727730
workInProgress.memoizedState = nextState;
728731
// Push the lanes that were skipped when we bailed out.
@@ -1345,13 +1348,6 @@ function updateHostRoot(current, workInProgress, renderLanes) {
13451348
}
13461349
}
13471350

1348-
if (enableTransitionTracing) {
1349-
// FIXME: Slipped past code review. This is not a safe mutation:
1350-
// workInProgress.memoizedState is a shared object. Need to fix before
1351-
// rolling out the Transition Tracing experiment.
1352-
workInProgress.memoizedState.transitions = getWorkInProgressTransitions();
1353-
}
1354-
13551351
// Caution: React DevTools currently depends on this property
13561352
// being called "element".
13571353
const nextChildren = nextState.element;
@@ -1365,6 +1361,7 @@ function updateHostRoot(current, workInProgress, renderLanes) {
13651361
element: nextChildren,
13661362
isDehydrated: false,
13671363
cache: nextState.cache,
1364+
pendingSuspenseBoundaries: nextState.pendingSuspenseBoundaries,
13681365
transitions: nextState.transitions,
13691366
};
13701367
const updateQueue: UpdateQueue<RootState> = (workInProgress.updateQueue: any);
@@ -1982,6 +1979,7 @@ function mountSuspenseOffscreenState(renderLanes: Lanes): OffscreenState {
19821979
return {
19831980
baseLanes: renderLanes,
19841981
cachePool: getSuspendedCache(),
1982+
transitions: null,
19851983
};
19861984
}
19871985

@@ -2016,6 +2014,7 @@ function updateSuspenseOffscreenState(
20162014
return {
20172015
baseLanes: mergeLanes(prevOffscreenState.baseLanes, renderLanes),
20182016
cachePool,
2017+
transitions: prevOffscreenState.transitions,
20192018
};
20202019
}
20212020

@@ -3582,9 +3581,6 @@ function attemptEarlyBailoutIfNoScheduledUpdate(
35823581
const cache: Cache = current.memoizedState.cache;
35833582
pushCacheProvider(workInProgress, cache);
35843583
}
3585-
if (enableTransitionTracing) {
3586-
workInProgress.memoizedState.transitions = getWorkInProgressTransitions();
3587-
}
35883584
resetHydrationState();
35893585
break;
35903586
case HostComponent:

packages/react-reconciler/src/ReactFiberBeginWork.old.js

+7-11
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,6 @@ import {
236236
markSkippedUpdateLanes,
237237
getWorkInProgressRoot,
238238
pushRenderLanes,
239-
getWorkInProgressTransitions,
240239
} from './ReactFiberWorkLoop.old';
241240
import {setWorkInProgressVersion} from './ReactMutableSource.old';
242241
import {pushCacheProvider, CacheContext} from './ReactFiberCacheComponent.old';
@@ -652,9 +651,11 @@ function updateOffscreenComponent(
652651
// Rendering a hidden tree.
653652
if ((workInProgress.mode & ConcurrentMode) === NoMode) {
654653
// In legacy sync mode, don't defer the subtree. Render it now.
654+
// TODO: Consider how Offscreen should work with transitions in the future
655655
const nextState: OffscreenState = {
656656
baseLanes: NoLanes,
657657
cachePool: null,
658+
transitions: null,
658659
};
659660
workInProgress.memoizedState = nextState;
660661
if (enableCache) {
@@ -688,6 +689,7 @@ function updateOffscreenComponent(
688689
const nextState: OffscreenState = {
689690
baseLanes: nextBaseLanes,
690691
cachePool: spawnedCachePool,
692+
transitions: null,
691693
};
692694
workInProgress.memoizedState = nextState;
693695
workInProgress.updateQueue = null;
@@ -723,6 +725,7 @@ function updateOffscreenComponent(
723725
const nextState: OffscreenState = {
724726
baseLanes: NoLanes,
725727
cachePool: null,
728+
transitions: null,
726729
};
727730
workInProgress.memoizedState = nextState;
728731
// Push the lanes that were skipped when we bailed out.
@@ -1345,13 +1348,6 @@ function updateHostRoot(current, workInProgress, renderLanes) {
13451348
}
13461349
}
13471350

1348-
if (enableTransitionTracing) {
1349-
// FIXME: Slipped past code review. This is not a safe mutation:
1350-
// workInProgress.memoizedState is a shared object. Need to fix before
1351-
// rolling out the Transition Tracing experiment.
1352-
workInProgress.memoizedState.transitions = getWorkInProgressTransitions();
1353-
}
1354-
13551351
// Caution: React DevTools currently depends on this property
13561352
// being called "element".
13571353
const nextChildren = nextState.element;
@@ -1365,6 +1361,7 @@ function updateHostRoot(current, workInProgress, renderLanes) {
13651361
element: nextChildren,
13661362
isDehydrated: false,
13671363
cache: nextState.cache,
1364+
pendingSuspenseBoundaries: nextState.pendingSuspenseBoundaries,
13681365
transitions: nextState.transitions,
13691366
};
13701367
const updateQueue: UpdateQueue<RootState> = (workInProgress.updateQueue: any);
@@ -1982,6 +1979,7 @@ function mountSuspenseOffscreenState(renderLanes: Lanes): OffscreenState {
19821979
return {
19831980
baseLanes: renderLanes,
19841981
cachePool: getSuspendedCache(),
1982+
transitions: null,
19851983
};
19861984
}
19871985

@@ -2016,6 +2014,7 @@ function updateSuspenseOffscreenState(
20162014
return {
20172015
baseLanes: mergeLanes(prevOffscreenState.baseLanes, renderLanes),
20182016
cachePool,
2017+
transitions: prevOffscreenState.transitions,
20192018
};
20202019
}
20212020

@@ -3582,9 +3581,6 @@ function attemptEarlyBailoutIfNoScheduledUpdate(
35823581
const cache: Cache = current.memoizedState.cache;
35833582
pushCacheProvider(workInProgress, cache);
35843583
}
3585-
if (enableTransitionTracing) {
3586-
workInProgress.memoizedState.transitions = getWorkInProgressTransitions();
3587-
}
35883584
resetHydrationState();
35893585
break;
35903586
case HostComponent:

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

+2-3
Original file line numberDiff line numberDiff line change
@@ -2725,9 +2725,8 @@ function commitPassiveMountOnFiber(
27252725
}
27262726

27272727
if (enableTransitionTracing) {
2728-
const transitions = finishedWork.memoizedState.transitions;
2729-
if (transitions !== null) {
2730-
transitions.forEach(transition => {
2728+
if (committedTransitions !== null) {
2729+
committedTransitions.forEach(transition => {
27312730
// TODO(luna) Do we want to log TransitionStart in the startTransition callback instead?
27322731
addTransitionStartCallbackToPendingTransition({
27332732
transitionName: transition.name,

packages/react-reconciler/src/ReactFiberCommitWork.old.js

+2-3
Original file line numberDiff line numberDiff line change
@@ -2725,9 +2725,8 @@ function commitPassiveMountOnFiber(
27252725
}
27262726

27272727
if (enableTransitionTracing) {
2728-
const transitions = finishedWork.memoizedState.transitions;
2729-
if (transitions !== null) {
2730-
transitions.forEach(transition => {
2728+
if (committedTransitions !== null) {
2729+
committedTransitions.forEach(transition => {
27312730
// TODO(luna) Do we want to log TransitionStart in the startTransition callback instead?
27322731
addTransitionStartCallbackToPendingTransition({
27332732
transitionName: transition.name,

packages/react-reconciler/src/ReactFiberOffscreenComponent.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import type {ReactNodeList, OffscreenMode} from 'shared/ReactTypes';
1111
import type {Lanes} from './ReactFiberLane.old';
1212
import type {SpawnedCachePool} from './ReactFiberCacheComponent.new';
13-
13+
import type {Transition} from './ReactFiberTracingMarkerComponent.new';
1414
export type OffscreenProps = {|
1515
// TODO: Pick an API before exposing the Offscreen type. I've chosen an enum
1616
// for now, since we might have multiple variants. For example, hiding the
@@ -30,6 +30,7 @@ export type OffscreenState = {|
3030
// order to unhide the component.
3131
baseLanes: Lanes,
3232
cachePool: SpawnedCachePool | null,
33+
transitions: Set<Transition> | null,
3334
|};
3435

3536
export type OffscreenInstance = {};

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

+8-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@ import type {
1515
} from './ReactInternalTypes';
1616
import type {RootTag} from './ReactRootTags';
1717
import type {Cache} from './ReactFiberCacheComponent.new';
18-
import type {Transition} from './ReactFiberTracingMarkerComponent.new';
18+
import type {
19+
PendingSuspenseBoundaries,
20+
Transition,
21+
} from './ReactFiberTracingMarkerComponent.new';
1922

2023
import {noTimeout, supportsHydration} from './ReactFiberHostConfig';
2124
import {createHostRootFiber} from './ReactFiber.new';
@@ -42,7 +45,8 @@ export type RootState = {
4245
element: any,
4346
isDehydrated: boolean,
4447
cache: Cache,
45-
transitions: Array<Transition> | null,
48+
pendingSuspenseBoundaries: PendingSuspenseBoundaries | null,
49+
transitions: Set<Transition> | null,
4650
};
4751

4852
function FiberRootNode(
@@ -184,6 +188,7 @@ export function createFiberRoot(
184188
isDehydrated: hydrate,
185189
cache: initialCache,
186190
transitions: null,
191+
pendingSuspenseBoundaries: null,
187192
};
188193
uninitializedFiber.memoizedState = initialState;
189194
} else {
@@ -192,6 +197,7 @@ export function createFiberRoot(
192197
isDehydrated: hydrate,
193198
cache: (null: any), // not enabled yet
194199
transitions: null,
200+
pendingSuspenseBoundaries: null,
195201
};
196202
uninitializedFiber.memoizedState = initialState;
197203
}

packages/react-reconciler/src/ReactFiberRoot.old.js

+8-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@ import type {
1515
} from './ReactInternalTypes';
1616
import type {RootTag} from './ReactRootTags';
1717
import type {Cache} from './ReactFiberCacheComponent.old';
18-
import type {Transition} from './ReactFiberTracingMarkerComponent.old';
18+
import type {
19+
PendingSuspenseBoundaries,
20+
Transition,
21+
} from './ReactFiberTracingMarkerComponent.old';
1922

2023
import {noTimeout, supportsHydration} from './ReactFiberHostConfig';
2124
import {createHostRootFiber} from './ReactFiber.old';
@@ -42,7 +45,8 @@ export type RootState = {
4245
element: any,
4346
isDehydrated: boolean,
4447
cache: Cache,
45-
transitions: Array<Transition> | null,
48+
pendingSuspenseBoundaries: PendingSuspenseBoundaries | null,
49+
transitions: Set<Transition> | null,
4650
};
4751

4852
function FiberRootNode(
@@ -184,6 +188,7 @@ export function createFiberRoot(
184188
isDehydrated: hydrate,
185189
cache: initialCache,
186190
transitions: null,
191+
pendingSuspenseBoundaries: null,
187192
};
188193
uninitializedFiber.memoizedState = initialState;
189194
} else {
@@ -192,6 +197,7 @@ export function createFiberRoot(
192197
isDehydrated: hydrate,
193198
cache: (null: any), // not enabled yet
194199
transitions: null,
200+
pendingSuspenseBoundaries: null,
195201
};
196202
uninitializedFiber.memoizedState = initialState;
197203
}

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

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export type SuspenseProps = {|
2929
suspenseCallback?: (Set<Wakeable> | null) => mixed,
3030

3131
unstable_expectedLoadTime?: number,
32+
unstable_name?: string,
3233
|};
3334

3435
// A null SuspenseState represents an unsuspended normal Suspense boundary.

packages/react-reconciler/src/ReactFiberSuspenseComponent.old.js

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export type SuspenseProps = {|
2929
suspenseCallback?: (Set<Wakeable> | null) => mixed,
3030

3131
unstable_expectedLoadTime?: number,
32+
unstable_name?: string,
3233
|};
3334

3435
// A null SuspenseState represents an unsuspended normal Suspense boundary.

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

+4-6
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@
77
* @flow
88
*/
99

10-
import type {TransitionTracingCallbacks} from './ReactInternalTypes';
11-
import type {Fiber} from 'react-reconciler/src/ReactInternalTypes';
10+
import type {TransitionTracingCallbacks, Fiber} from './ReactInternalTypes';
11+
import type {OffscreenInstance} from './ReactFiberOffscreenComponent';
12+
1213
import {enableTransitionTracing} from 'shared/ReactFeatureFlags';
1314

1415
export type SuspenseInfo = {name: string | null};
@@ -34,10 +35,7 @@ export type BatchConfigTransition = {
3435
_updatedFibers?: Set<Fiber>,
3536
};
3637

37-
export type TransitionCallback = 0 | 1;
38-
39-
export const TransitionStart = 0;
40-
export const TransitionComplete = 1;
38+
export type PendingSuspenseBoundaries = Map<OffscreenInstance, SuspenseInfo>;
4139

4240
export function processTransitionCallbacks(
4341
pendingTransitions: PendingTransitionCallbacks,

packages/react-reconciler/src/ReactFiberTracingMarkerComponent.old.js

+4-6
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@
77
* @flow
88
*/
99

10-
import type {TransitionTracingCallbacks} from './ReactInternalTypes';
11-
import type {Fiber} from 'react-reconciler/src/ReactInternalTypes';
10+
import type {TransitionTracingCallbacks, Fiber} from './ReactInternalTypes';
11+
import type {OffscreenInstance} from './ReactFiberOffscreenComponent';
12+
1213
import {enableTransitionTracing} from 'shared/ReactFeatureFlags';
1314

1415
export type SuspenseInfo = {name: string | null};
@@ -34,10 +35,7 @@ export type BatchConfigTransition = {
3435
_updatedFibers?: Set<Fiber>,
3536
};
3637

37-
export type TransitionCallback = 0 | 1;
38-
39-
export const TransitionStart = 0;
40-
export const TransitionComplete = 1;
38+
export type PendingSuspenseBoundaries = Map<OffscreenInstance, SuspenseInfo>;
4139

4240
export function processTransitionCallbacks(
4341
pendingTransitions: PendingTransitionCallbacks,

0 commit comments

Comments
 (0)