Skip to content

Commit a4647fa

Browse files
committed
transition tracing delete tracing marker
1 parent 17e2a15 commit a4647fa

File tree

7 files changed

+673
-9
lines changed

7 files changed

+673
-9
lines changed

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -772,6 +772,9 @@ export function createFiberFromTracingMarker(
772772
const tracingMarkerInstance: TracingMarkerInstance = {
773773
transitions: null,
774774
pendingBoundaries: null,
775+
deletions: null,
776+
parents: null,
777+
name: pendingProps.name,
775778
};
776779
fiber.stateNode = tracingMarkerInstance;
777780
return fiber;

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -979,6 +979,7 @@ function updateTracingMarkerComponent(
979979
transitions: new Set(currentTransitions),
980980
pendingBoundaries: new Map(),
981981
name: workInProgress.pendingProps.name,
982+
deletions: null,
982983
};
983984
workInProgress.stateNode = markerInstance;
984985
}

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

Lines changed: 147 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@ import type {
3030
import type {HookFlags} from './ReactHookEffectTags';
3131
import type {Cache} from './ReactFiberCacheComponent.new';
3232
import type {RootState} from './ReactFiberRoot.new';
33-
import type {Transition} from './ReactFiberTracingMarkerComponent.new';
33+
import type {
34+
Transition,
35+
TracingMarkerInstance,
36+
} from './ReactFiberTracingMarkerComponent.new';
3437

3538
import {
3639
enableCreateEventHandleAPI,
@@ -146,6 +149,7 @@ import {
146149
addTransitionProgressCallbackToPendingTransition,
147150
addTransitionCompleteCallbackToPendingTransition,
148151
addMarkerProgressCallbackToPendingTransition,
152+
addMarkerIncompleteCallbackToPendingTransition,
149153
addMarkerCompleteCallbackToPendingTransition,
150154
setIsRunningInsertionEffect,
151155
} from './ReactFiberWorkLoop.new';
@@ -1132,6 +1136,98 @@ function commitLayoutEffectOnFiber(
11321136
}
11331137
}
11341138

1139+
function abortParentMarkerTransitions(
1140+
fiber,
1141+
deletedFiber,
1142+
deletion,
1143+
isDeleted,
1144+
) {
1145+
const instance = deletedFiber.stateNode;
1146+
switch (fiber.tag) {
1147+
case TracingMarkerComponent:
1148+
const transitions = Array.from(deletedFiber.stateNode.transitions);
1149+
1150+
const markerInstance = fiber.stateNode;
1151+
const markerTransitions = markerInstance.transitions;
1152+
const abortMarker = transitions.some(transition =>
1153+
markerTransitions.has(transition),
1154+
);
1155+
1156+
if (abortMarker) {
1157+
if (markerInstance.deletions === null) {
1158+
markerInstance.deletions = new Set();
1159+
}
1160+
1161+
markerInstance.deletions.add(deletion);
1162+
addMarkerIncompleteCallbackToPendingTransition(
1163+
fiber.memoizedProps.name,
1164+
transitions,
1165+
markerInstance.deletions,
1166+
);
1167+
1168+
if (
1169+
!isDeleted &&
1170+
markerInstance.pendingBoundaries !== null &&
1171+
markerInstance.pendingBoundaries.has(instance)
1172+
) {
1173+
markerInstance.pendingBoundaries.delete(instance);
1174+
1175+
addMarkerProgressCallbackToPendingTransition(
1176+
markerInstance.name,
1177+
transitions,
1178+
markerInstance.pendingBoundaries,
1179+
);
1180+
}
1181+
}
1182+
break;
1183+
case HostRoot:
1184+
const root = fiber.stateNode;
1185+
const incompleteTransitions = root.incompleteTransitions;
1186+
1187+
instance.transitions.forEach(transition => {
1188+
if (incompleteTransitions.has(transition)) {
1189+
const transitionInstance = incompleteTransitions.get(transition);
1190+
if (transitionInstance.deletions === null) {
1191+
transitionInstance.deletions = [];
1192+
}
1193+
transitionInstance.deletions.push(deletion);
1194+
1195+
if (
1196+
transitionInstance.pendingBoundaries !== null &&
1197+
transitionInstance.pendingBoundaries.has(instance)
1198+
) {
1199+
transitionInstance.pendingBoundaries.delete(instance);
1200+
}
1201+
}
1202+
});
1203+
break;
1204+
default:
1205+
break;
1206+
}
1207+
}
1208+
1209+
function recursivelyAbortParentMarkerTransitions(
1210+
deletedFiber: Fiber,
1211+
nearestMountedAncestor,
1212+
deletion,
1213+
) {
1214+
let fiber = deletedFiber;
1215+
while (fiber !== null) {
1216+
abortParentMarkerTransitions(fiber, deletedFiber, deletion, true);
1217+
if (nearestMountedAncestor.deletions.includes(fiber)) {
1218+
break;
1219+
} else {
1220+
fiber = fiber.return;
1221+
}
1222+
}
1223+
1224+
fiber = nearestMountedAncestor;
1225+
while (fiber !== null) {
1226+
abortParentMarkerTransitions(fiber, deletedFiber, deletion, false);
1227+
fiber = fiber.return;
1228+
}
1229+
}
1230+
11351231
function commitTransitionProgress(offscreenFiber: Fiber) {
11361232
if (enableTransitionTracing) {
11371233
// This function adds suspense boundaries to the root
@@ -1987,6 +2083,20 @@ function commitDeletionEffectsOnFiber(
19872083
const prevOffscreenSubtreeWasHidden = offscreenSubtreeWasHidden;
19882084
offscreenSubtreeWasHidden =
19892085
prevOffscreenSubtreeWasHidden || deletedFiber.memoizedState !== null;
2086+
2087+
if (enableTransitionTracing) {
2088+
// We need to mark this fiber's parents as deleted
2089+
const instance: OffscreenInstance = deletedFiber.stateNode;
2090+
const markers = instance.pendingMarkers;
2091+
if (markers !== null) {
2092+
markers.forEach(marker => {
2093+
if (marker.pendingBoundaries.has(instance)) {
2094+
marker.pendingBoundaries.delete(instance);
2095+
}
2096+
});
2097+
}
2098+
}
2099+
19902100
recursivelyTraverseDeletionEffects(
19912101
finishedRoot,
19922102
nearestMountedAncestor,
@@ -2002,6 +2112,30 @@ function commitDeletionEffectsOnFiber(
20022112
}
20032113
break;
20042114
}
2115+
case TracingMarkerComponent: {
2116+
if (enableTransitionTracing) {
2117+
// We need to mark this fiber's parents as deleted
2118+
const instance: TracingMarkerInstance = deletedFiber.stateNode;
2119+
const transitions = instance.transitions;
2120+
if (transitions !== null) {
2121+
const deletion = {
2122+
type: 'marker',
2123+
name: deletedFiber.memoizedProps.name,
2124+
};
2125+
recursivelyAbortParentMarkerTransitions(
2126+
deletedFiber,
2127+
nearestMountedAncestor,
2128+
deletion,
2129+
);
2130+
}
2131+
}
2132+
recursivelyTraverseDeletionEffects(
2133+
finishedRoot,
2134+
nearestMountedAncestor,
2135+
deletedFiber,
2136+
);
2137+
return;
2138+
}
20052139
default: {
20062140
recursivelyTraverseDeletionEffects(
20072141
finishedRoot,
@@ -2987,6 +3121,11 @@ function commitOffscreenPassiveMountEffects(
29873121
}
29883122

29893123
commitTransitionProgress(finishedWork);
3124+
3125+
if (!isHidden) {
3126+
instance.transitions = null;
3127+
instance.pendingMarkers = null;
3128+
}
29903129
}
29913130
}
29923131

@@ -3023,14 +3162,16 @@ function commitTracingMarkerPassiveMountEffect(finishedWork: Fiber) {
30233162
(instance.pendingBoundaries === null ||
30243163
instance.pendingBoundaries.size === 0)
30253164
) {
3026-
instance.transitions.forEach(transition => {
3165+
if (instance.deletions === null) {
30273166
addMarkerCompleteCallbackToPendingTransition(
30283167
finishedWork.memoizedProps.name,
30293168
instance.transitions,
30303169
);
3031-
});
3170+
}
30323171
instance.transitions = null;
30333172
instance.pendingBoundaries = null;
3173+
instance.deletions = null;
3174+
instance.name = null;
30343175
}
30353176
}
30363177

@@ -3146,7 +3287,9 @@ function commitPassiveMountOnFiber(
31463287
incompleteTransitions.forEach((markerInstance, transition) => {
31473288
const pendingBoundaries = markerInstance.pendingBoundaries;
31483289
if (pendingBoundaries === null || pendingBoundaries.size === 0) {
3149-
addTransitionCompleteCallbackToPendingTransition(transition);
3290+
if (markerInstance.deletions === null) {
3291+
addTransitionCompleteCallbackToPendingTransition(transition);
3292+
}
31503293
incompleteTransitions.delete(transition);
31513294
}
31523295
});

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

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,14 @@ export type PendingTransitionCallbacks = {
2121
transitionStart: Array<Transition> | null,
2222
transitionProgress: Map<Transition, PendingBoundaries> | null,
2323
transitionComplete: Array<Transition> | null,
24-
markerProgress: Map<string, TracingMarkerInstance> | null,
24+
markerProgress: Map<
25+
string,
26+
{pendingBoundaries: PendingBoundaries, transitions: Set<Transition>},
27+
> | null,
28+
markerIncomplete: Map<
29+
string,
30+
{deletions: Array<TransitionDeletion>, transitions: Set<Transition>},
31+
> | null,
2532
markerComplete: Map<string, Set<Transition>> | null,
2633
};
2734

@@ -39,7 +46,14 @@ export type BatchConfigTransition = {
3946
export type TracingMarkerInstance = {|
4047
pendingBoundaries: PendingBoundaries | null,
4148
transitions: Set<Transition> | null,
42-
name?: string,
49+
deletions: Array<TransitionDeletion> | null,
50+
name: string | null,
51+
|};
52+
53+
export type TransitionDeletion = {|
54+
type: 'error' | 'unknown' | 'marker' | 'suspense',
55+
name?: string | null,
56+
transitions: Set<Transition>,
4357
|};
4458

4559
export type PendingBoundaries = Map<OffscreenInstance, SuspenseInfo>;
@@ -64,6 +78,7 @@ export function processTransitionCallbacks(
6478
if (onMarkerProgress != null && markerProgress !== null) {
6579
markerProgress.forEach((markerInstance, markerName) => {
6680
if (markerInstance.transitions !== null) {
81+
// TODO: Clone the suspense object so users can't modify it
6782
const pending =
6883
markerInstance.pendingBoundaries !== null
6984
? Array.from(markerInstance.pendingBoundaries.values())
@@ -96,6 +111,31 @@ export function processTransitionCallbacks(
96111
});
97112
}
98113

114+
const markerIncomplete = pendingTransitions.markerIncomplete;
115+
const onMarkerIncomplete = callbacks.onMarkerIncomplete;
116+
if (onMarkerIncomplete != null && markerIncomplete !== null) {
117+
markerIncomplete.forEach(({transitions, deletions}, markerName) => {
118+
transitions.forEach(transition => {
119+
const filteredDeletions = [];
120+
deletions.forEach(deletion => {
121+
const filteredDeletion = getFilteredDeletion(deletion, endTime);
122+
if (filteredDeletion !== null) {
123+
filteredDeletions.push(filteredDeletion);
124+
}
125+
});
126+
127+
if (filteredDeletions.length > 0) {
128+
onMarkerIncomplete(
129+
transition.name,
130+
markerName,
131+
transition.startTime,
132+
filteredDeletions,
133+
);
134+
}
135+
});
136+
});
137+
}
138+
99139
const transitionProgress = pendingTransitions.transitionProgress;
100140
const onTransitionProgress = callbacks.onTransitionProgress;
101141
if (onTransitionProgress != null && transitionProgress !== null) {
@@ -120,6 +160,21 @@ export function processTransitionCallbacks(
120160
}
121161
}
122162

163+
function getFilteredDeletion(deletion: TransitionDeletion, endTime: number) {
164+
switch (deletion.type) {
165+
case 'marker': {
166+
return {
167+
type: deletion.type,
168+
name: deletion.name,
169+
endTime,
170+
};
171+
}
172+
default: {
173+
return null;
174+
}
175+
}
176+
}
177+
123178
// For every tracing marker, store a pointer to it. We will later access it
124179
// to get the set of suspense boundaries that need to resolve before the
125180
// tracing marker can be logged as complete
@@ -148,6 +203,9 @@ export function pushRootMarkerInstance(workInProgress: Fiber): void {
148203
const markerInstance: TracingMarkerInstance = {
149204
transitions: new Set([transition]),
150205
pendingBoundaries: null,
206+
deletions: null,
207+
parents: null,
208+
name: null,
151209
};
152210
root.incompleteTransitions.set(transition, markerInstance);
153211
}

0 commit comments

Comments
 (0)