Skip to content

Commit cccc144

Browse files
committed
When one or more async transitions are on going add all transition types to every root that gets scheduled
1 parent 66a7a4d commit cccc144

File tree

3 files changed

+64
-14
lines changed

3 files changed

+64
-14
lines changed

packages/react-reconciler/src/ReactFiberAsyncAction.js

+2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import {
2525
enableComponentPerformanceTrack,
2626
enableProfilerTimer,
2727
} from 'shared/ReactFeatureFlags';
28+
import {clearEntangledAsyncTransitionTypes} from './ReactFiberTransitionTypes';
2829

2930
// If there are multiple, concurrent async actions, they are entangled. All
3031
// transition updates that occur while the async action is still in progress
@@ -84,6 +85,7 @@ function pingEngtangledActionScope() {
8485
clearAsyncTransitionTimer();
8586
}
8687
}
88+
clearEntangledAsyncTransitionTypes();
8789
if (currentEntangledListeners !== null) {
8890
// All the actions have finished. Close the entangled async action scope
8991
// and notify all the listeners.

packages/react-reconciler/src/ReactFiberTransition.js

+35-12
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import type {
1212
GestureProvider,
1313
GestureOptions,
1414
} from 'shared/ReactTypes';
15-
import type {Lanes} from './ReactFiberLane';
15+
import {NoLane, type Lanes} from './ReactFiberLane';
1616
import type {StackCursor} from './ReactFiberStack';
1717
import type {Cache, SpawnedCachePool} from './ReactFiberCacheComponent';
1818
import type {Transition} from 'react/src/ReactStartTransition';
@@ -34,10 +34,17 @@ import {
3434
retainCache,
3535
CacheContext,
3636
} from './ReactFiberCacheComponent';
37-
import {queueTransitionTypes} from './ReactFiberTransitionTypes';
37+
import {
38+
queueTransitionTypes,
39+
entangleAsyncTransitionTypes,
40+
entangledTransitionTypes,
41+
} from './ReactFiberTransitionTypes';
3842

3943
import ReactSharedInternals from 'shared/ReactSharedInternals';
40-
import {entangleAsyncAction} from './ReactFiberAsyncAction';
44+
import {
45+
entangleAsyncAction,
46+
peekEntangledActionLane,
47+
} from './ReactFiberAsyncAction';
4148
import {startAsyncTransitionTimer} from './ReactProfilerTimer';
4249
import {firstScheduledRoot} from './ReactFiberRootScheduler';
4350
import {
@@ -88,15 +95,31 @@ ReactSharedInternals.S = function onStartTransitionFinishForReconciler(
8895
const thenable: Thenable<mixed> = (returnValue: any);
8996
entangleAsyncAction(transition, thenable);
9097
}
91-
if (enableViewTransition && transition.types !== null) {
92-
// Within this Transition we should've now scheduled any roots we have updates
93-
// to work on. If there are no updates on a root, then the Transition type won't
94-
// be applied to that root.
95-
// TODO: The exception is if we're to an async action, the updates might come in later.
96-
let root = firstScheduledRoot;
97-
while (root !== null) {
98-
queueTransitionTypes(root, transition.types);
99-
root = root.next;
98+
if (enableViewTransition) {
99+
if (entangledTransitionTypes !== null) {
100+
// If we scheduled work on any new roots, we need to add any entangled async
101+
// transition types to those roots too.
102+
let root = firstScheduledRoot;
103+
while (root !== null) {
104+
queueTransitionTypes(root, entangledTransitionTypes);
105+
root = root.next;
106+
}
107+
}
108+
const transitionTypes = transition.types;
109+
if (transitionTypes !== null) {
110+
// Within this Transition we should've now scheduled any roots we have updates
111+
// to work on. If there are no updates on a root, then the Transition type won't
112+
// be applied to that root.
113+
let root = firstScheduledRoot;
114+
while (root !== null) {
115+
queueTransitionTypes(root, transitionTypes);
116+
root = root.next;
117+
}
118+
if (peekEntangledActionLane() !== NoLane) {
119+
// If we have entangled, async actions going on, the update associated with
120+
// these types might come later. We need to save them for later.
121+
entangleAsyncTransitionTypes(transitionTypes);
122+
}
100123
}
101124
}
102125
if (prevOnStartTransitionFinish !== null) {

packages/react-reconciler/src/ReactFiberTransitionTypes.js

+27-2
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ import {enableViewTransition} from 'shared/ReactFeatureFlags';
1414

1515
export function queueTransitionTypes(
1616
root: FiberRoot,
17-
transitionTypes: null | TransitionTypes,
17+
transitionTypes: TransitionTypes,
1818
): void {
19-
if (enableViewTransition && transitionTypes !== null) {
19+
if (enableViewTransition) {
2020
// TODO: We should really store transitionTypes per lane in a LaneMap on
2121
// the root. Then merge it when we commit. We currently assume that all
2222
// Transitions are entangled.
@@ -33,6 +33,31 @@ export function queueTransitionTypes(
3333
}
3434
}
3535

36+
// Store all types while we're entangled with an async Transition.
37+
export let entangledTransitionTypes: null | TransitionTypes = null;
38+
39+
export function entangleAsyncTransitionTypes(
40+
transitionTypes: TransitionTypes,
41+
): void {
42+
if (enableViewTransition) {
43+
let queued = entangledTransitionTypes;
44+
if (queued === null) {
45+
queued = entangledTransitionTypes = [];
46+
}
47+
for (let i = 0; i < transitionTypes.length; i++) {
48+
const transitionType = transitionTypes[i];
49+
if (queued.indexOf(transitionType) === -1) {
50+
queued.push(transitionType);
51+
}
52+
}
53+
}
54+
}
55+
56+
export function clearEntangledAsyncTransitionTypes() {
57+
// Called when all Async Actions are done.
58+
entangledTransitionTypes = null;
59+
}
60+
3661
export function claimQueuedTransitionTypes(
3762
root: FiberRoot,
3863
): null | TransitionTypes {

0 commit comments

Comments
 (0)