Skip to content

Commit a4bed46

Browse files
authored
[Transition Tracing] Add Tracing Markers (#24686)
This PR adds support for Tracing Markers as well as onTracingMarkerComplete
1 parent 1678530 commit a4bed46

14 files changed

+543
-12
lines changed

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import type {
1919
OffscreenProps,
2020
OffscreenInstance,
2121
} from './ReactFiberOffscreenComponent';
22+
import type {TracingMarkerInstance} from './ReactFiberTracingMarkerComponent.new';
2223

2324
import {
2425
createRootStrictEffectsByDefault,
@@ -757,6 +758,11 @@ export function createFiberFromTracingMarker(
757758
const fiber = createFiber(TracingMarkerComponent, pendingProps, key, mode);
758759
fiber.elementType = REACT_TRACING_MARKER_TYPE;
759760
fiber.lanes = lanes;
761+
const tracingMarkerInstance: TracingMarkerInstance = {
762+
transitions: null,
763+
pendingSuspenseBoundaries: null,
764+
};
765+
fiber.stateNode = tracingMarkerInstance;
760766
return fiber;
761767
}
762768

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import type {
1919
OffscreenProps,
2020
OffscreenInstance,
2121
} from './ReactFiberOffscreenComponent';
22+
import type {TracingMarkerInstance} from './ReactFiberTracingMarkerComponent.old';
2223

2324
import {
2425
createRootStrictEffectsByDefault,
@@ -757,6 +758,11 @@ export function createFiberFromTracingMarker(
757758
const fiber = createFiber(TracingMarkerComponent, pendingProps, key, mode);
758759
fiber.elementType = REACT_TRACING_MARKER_TYPE;
759760
fiber.lanes = lanes;
761+
const tracingMarkerInstance: TracingMarkerInstance = {
762+
transitions: null,
763+
pendingSuspenseBoundaries: null,
764+
};
765+
fiber.stateNode = tracingMarkerInstance;
760766
return fiber;
761767
}
762768

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

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import type {
3535
} from './ReactFiberCacheComponent.new';
3636
import type {UpdateQueue} from './ReactFiberClassUpdateQueue.new';
3737
import type {RootState} from './ReactFiberRoot.new';
38+
import type {TracingMarkerInstance} from './ReactFiberTracingMarkerComponent.new';
3839
import {
3940
enableSuspenseAvoidThisFallback,
4041
enableCPUSuspense,
@@ -255,9 +256,12 @@ import {
255256
getSuspendedCache,
256257
pushTransition,
257258
getOffscreenDeferredCache,
258-
getSuspendedTransitions,
259+
getPendingTransitions,
259260
} from './ReactFiberTransition.new';
260-
import {pushTracingMarker} from './ReactFiberTracingMarkerComponent.new';
261+
import {
262+
getTracingMarkers,
263+
pushTracingMarker,
264+
} from './ReactFiberTracingMarkerComponent.new';
261265

262266
const ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner;
263267

@@ -891,6 +895,20 @@ function updateTracingMarkerComponent(
891895
return null;
892896
}
893897

898+
// TODO: (luna) Only update the tracing marker if it's newly rendered or it's name changed.
899+
// A tracing marker is only associated with the transitions that rendered
900+
// or updated it, so we can create a new set of transitions each time
901+
if (current === null) {
902+
const currentTransitions = getPendingTransitions();
903+
if (currentTransitions !== null) {
904+
const markerInstance: TracingMarkerInstance = {
905+
transitions: new Set(currentTransitions),
906+
pendingSuspenseBoundaries: new Map(),
907+
};
908+
workInProgress.stateNode = markerInstance;
909+
}
910+
}
911+
894912
pushTracingMarker(workInProgress);
895913
const nextChildren = workInProgress.pendingProps.children;
896914
reconcileChildren(current, workInProgress, nextChildren, renderLanes);
@@ -2093,10 +2111,13 @@ function updateSuspenseComponent(current, workInProgress, renderLanes) {
20932111
);
20942112
workInProgress.memoizedState = SUSPENDED_MARKER;
20952113
if (enableTransitionTracing) {
2096-
const currentTransitions = getSuspendedTransitions();
2114+
const currentTransitions = getPendingTransitions();
20972115
if (currentTransitions !== null) {
2116+
// If there are no transitions, we don't need to keep track of tracing markers
2117+
const currentTracingMarkers = getTracingMarkers();
20982118
const primaryChildUpdateQueue: OffscreenQueue = {
20992119
transitions: currentTransitions,
2120+
tracingMarkers: currentTracingMarkers,
21002121
};
21012122
primaryChildFragment.updateQueue = primaryChildUpdateQueue;
21022123
}
@@ -2177,10 +2198,12 @@ function updateSuspenseComponent(current, workInProgress, renderLanes) {
21772198
? mountSuspenseOffscreenState(renderLanes)
21782199
: updateSuspenseOffscreenState(prevOffscreenState, renderLanes);
21792200
if (enableTransitionTracing) {
2180-
const currentTransitions = getSuspendedTransitions();
2201+
const currentTransitions = getPendingTransitions();
21812202
if (currentTransitions !== null) {
2203+
const currentTracingMarkers = getTracingMarkers();
21822204
const primaryChildUpdateQueue: OffscreenQueue = {
21832205
transitions: currentTransitions,
2206+
tracingMarkers: currentTracingMarkers,
21842207
};
21852208
primaryChildFragment.updateQueue = primaryChildUpdateQueue;
21862209
}

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

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import type {
3535
} from './ReactFiberCacheComponent.old';
3636
import type {UpdateQueue} from './ReactFiberClassUpdateQueue.old';
3737
import type {RootState} from './ReactFiberRoot.old';
38+
import type {TracingMarkerInstance} from './ReactFiberTracingMarkerComponent.old';
3839
import {
3940
enableSuspenseAvoidThisFallback,
4041
enableCPUSuspense,
@@ -255,9 +256,12 @@ import {
255256
getSuspendedCache,
256257
pushTransition,
257258
getOffscreenDeferredCache,
258-
getSuspendedTransitions,
259+
getPendingTransitions,
259260
} from './ReactFiberTransition.old';
260-
import {pushTracingMarker} from './ReactFiberTracingMarkerComponent.old';
261+
import {
262+
getTracingMarkers,
263+
pushTracingMarker,
264+
} from './ReactFiberTracingMarkerComponent.old';
261265

262266
const ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner;
263267

@@ -891,6 +895,20 @@ function updateTracingMarkerComponent(
891895
return null;
892896
}
893897

898+
// TODO: (luna) Only update the tracing marker if it's newly rendered or it's name changed.
899+
// A tracing marker is only associated with the transitions that rendered
900+
// or updated it, so we can create a new set of transitions each time
901+
if (current === null) {
902+
const currentTransitions = getPendingTransitions();
903+
if (currentTransitions !== null) {
904+
const markerInstance: TracingMarkerInstance = {
905+
transitions: new Set(currentTransitions),
906+
pendingSuspenseBoundaries: new Map(),
907+
};
908+
workInProgress.stateNode = markerInstance;
909+
}
910+
}
911+
894912
pushTracingMarker(workInProgress);
895913
const nextChildren = workInProgress.pendingProps.children;
896914
reconcileChildren(current, workInProgress, nextChildren, renderLanes);
@@ -2093,10 +2111,13 @@ function updateSuspenseComponent(current, workInProgress, renderLanes) {
20932111
);
20942112
workInProgress.memoizedState = SUSPENDED_MARKER;
20952113
if (enableTransitionTracing) {
2096-
const currentTransitions = getSuspendedTransitions();
2114+
const currentTransitions = getPendingTransitions();
20972115
if (currentTransitions !== null) {
2116+
// If there are no transitions, we don't need to keep track of tracing markers
2117+
const currentTracingMarkers = getTracingMarkers();
20982118
const primaryChildUpdateQueue: OffscreenQueue = {
20992119
transitions: currentTransitions,
2120+
tracingMarkers: currentTracingMarkers,
21002121
};
21012122
primaryChildFragment.updateQueue = primaryChildUpdateQueue;
21022123
}
@@ -2177,10 +2198,12 @@ function updateSuspenseComponent(current, workInProgress, renderLanes) {
21772198
? mountSuspenseOffscreenState(renderLanes)
21782199
: updateSuspenseOffscreenState(prevOffscreenState, renderLanes);
21792200
if (enableTransitionTracing) {
2180-
const currentTransitions = getSuspendedTransitions();
2201+
const currentTransitions = getPendingTransitions();
21812202
if (currentTransitions !== null) {
2203+
const currentTracingMarkers = getTracingMarkers();
21822204
const primaryChildUpdateQueue: OffscreenQueue = {
21832205
transitions: currentTransitions,
2206+
tracingMarkers: currentTracingMarkers,
21842207
};
21852208
primaryChildFragment.updateQueue = primaryChildUpdateQueue;
21862209
}

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

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ import {
138138
restorePendingUpdaters,
139139
addTransitionStartCallbackToPendingTransition,
140140
addTransitionCompleteCallbackToPendingTransition,
141+
addMarkerCompleteCallbackToPendingTransition,
141142
setIsRunningInsertionEffect,
142143
} from './ReactFiberWorkLoop.new';
143144
import {
@@ -2910,6 +2911,7 @@ function commitPassiveMountOnFiber(
29102911
instance.transitions = prevTransitions = new Set();
29112912
}
29122913

2914+
// TODO(luna): Combine the root code with the tracing marker code
29132915
if (transitions !== null) {
29142916
transitions.forEach(transition => {
29152917
// Add all the transitions saved in the update queue during
@@ -2931,6 +2933,23 @@ function commitPassiveMountOnFiber(
29312933
}
29322934
});
29332935
}
2936+
2937+
const tracingMarkers = queue.tracingMarkers;
2938+
if (tracingMarkers !== null) {
2939+
tracingMarkers.forEach(marker => {
2940+
const markerInstance = marker.stateNode;
2941+
// There should only be a few tracing marker transitions because
2942+
// they should be only associated with the transition that
2943+
// caused them
2944+
markerInstance.transitions.forEach(transition => {
2945+
if (instance.transitions.has(transition)) {
2946+
instance.pendingMarkers.add(
2947+
markerInstance.pendingSuspenseBoundaries,
2948+
);
2949+
}
2950+
});
2951+
});
2952+
}
29342953
}
29352954

29362955
commitTransitionProgress(finishedWork);
@@ -2967,6 +2986,28 @@ function commitPassiveMountOnFiber(
29672986
}
29682987
break;
29692988
}
2989+
case TracingMarkerComponent: {
2990+
if (enableTransitionTracing) {
2991+
// Get the transitions that were initiatized during the render
2992+
// and add a start transition callback for each of them
2993+
const instance = finishedWork.stateNode;
2994+
if (
2995+
instance.pendingSuspenseBoundaries === null ||
2996+
instance.pendingSuspenseBoundaries.size === 0
2997+
) {
2998+
instance.transitions.forEach(transition => {
2999+
addMarkerCompleteCallbackToPendingTransition({
3000+
transitionName: transition.name,
3001+
startTime: transition.startTime,
3002+
markerName: finishedWork.memoizedProps.name,
3003+
});
3004+
});
3005+
instance.transitions = null;
3006+
instance.pendingSuspenseBoundaries = null;
3007+
}
3008+
}
3009+
break;
3010+
}
29703011
}
29713012
}
29723013

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

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ import {
138138
restorePendingUpdaters,
139139
addTransitionStartCallbackToPendingTransition,
140140
addTransitionCompleteCallbackToPendingTransition,
141+
addMarkerCompleteCallbackToPendingTransition,
141142
setIsRunningInsertionEffect,
142143
} from './ReactFiberWorkLoop.old';
143144
import {
@@ -2910,6 +2911,7 @@ function commitPassiveMountOnFiber(
29102911
instance.transitions = prevTransitions = new Set();
29112912
}
29122913

2914+
// TODO(luna): Combine the root code with the tracing marker code
29132915
if (transitions !== null) {
29142916
transitions.forEach(transition => {
29152917
// Add all the transitions saved in the update queue during
@@ -2931,6 +2933,23 @@ function commitPassiveMountOnFiber(
29312933
}
29322934
});
29332935
}
2936+
2937+
const tracingMarkers = queue.tracingMarkers;
2938+
if (tracingMarkers !== null) {
2939+
tracingMarkers.forEach(marker => {
2940+
const markerInstance = marker.stateNode;
2941+
// There should only be a few tracing marker transitions because
2942+
// they should be only associated with the transition that
2943+
// caused them
2944+
markerInstance.transitions.forEach(transition => {
2945+
if (instance.transitions.has(transition)) {
2946+
instance.pendingMarkers.add(
2947+
markerInstance.pendingSuspenseBoundaries,
2948+
);
2949+
}
2950+
});
2951+
});
2952+
}
29342953
}
29352954

29362955
commitTransitionProgress(finishedWork);
@@ -2967,6 +2986,28 @@ function commitPassiveMountOnFiber(
29672986
}
29682987
break;
29692988
}
2989+
case TracingMarkerComponent: {
2990+
if (enableTransitionTracing) {
2991+
// Get the transitions that were initiatized during the render
2992+
// and add a start transition callback for each of them
2993+
const instance = finishedWork.stateNode;
2994+
if (
2995+
instance.pendingSuspenseBoundaries === null ||
2996+
instance.pendingSuspenseBoundaries.size === 0
2997+
) {
2998+
instance.transitions.forEach(transition => {
2999+
addMarkerCompleteCallbackToPendingTransition({
3000+
transitionName: transition.name,
3001+
startTime: transition.startTime,
3002+
markerName: finishedWork.memoizedProps.name,
3003+
});
3004+
});
3005+
instance.transitions = null;
3006+
instance.pendingSuspenseBoundaries = null;
3007+
}
3008+
}
3009+
break;
3010+
}
29703011
}
29713012
}
29723013

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1581,9 +1581,18 @@ function completeWork(
15811581
}
15821582
case TracingMarkerComponent: {
15831583
if (enableTransitionTracing) {
1584-
// Bubble subtree flags before so we can set the flag property
15851584
popTracingMarker(workInProgress);
15861585
bubbleProperties(workInProgress);
1586+
1587+
if (
1588+
current === null ||
1589+
(workInProgress.subtreeFlags & Visibility) !== NoFlags
1590+
) {
1591+
// If any of our suspense children toggle visibility, this means that
1592+
// the pending boundaries array needs to be updated, which we only
1593+
// do in the passive phase.
1594+
workInProgress.flags |= Passive;
1595+
}
15871596
}
15881597
return null;
15891598
}

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1581,9 +1581,18 @@ function completeWork(
15811581
}
15821582
case TracingMarkerComponent: {
15831583
if (enableTransitionTracing) {
1584-
// Bubble subtree flags before so we can set the flag property
15851584
popTracingMarker(workInProgress);
15861585
bubbleProperties(workInProgress);
1586+
1587+
if (
1588+
current === null ||
1589+
(workInProgress.subtreeFlags & Visibility) !== NoFlags
1590+
) {
1591+
// If any of our suspense children toggle visibility, this means that
1592+
// the pending boundaries array needs to be updated, which we only
1593+
// do in the passive phase.
1594+
workInProgress.flags |= Passive;
1595+
}
15871596
}
15881597
return null;
15891598
}

packages/react-reconciler/src/ReactFiberOffscreenComponent.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
*/
99

1010
import type {ReactNodeList, OffscreenMode} from 'shared/ReactTypes';
11+
import type {Fiber} from './ReactInternalTypes';
1112
import type {Lanes} from './ReactFiberLane.old';
1213
import type {SpawnedCachePool} from './ReactFiberCacheComponent.new';
1314
import type {
@@ -38,6 +39,7 @@ export type OffscreenState = {|
3839

3940
export type OffscreenQueue = {|
4041
transitions: Array<Transition> | null,
42+
tracingMarkers: Array<Fiber> | null,
4143
|} | null;
4244

4345
export type OffscreenInstance = {|

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ export type BatchConfigTransition = {
3939
_updatedFibers?: Set<Fiber>,
4040
};
4141

42+
export type TracingMarkerInstance = {|
43+
pendingSuspenseBoundaries: PendingSuspenseBoundaries | null,
44+
transitions: Set<Transition> | null,
45+
|} | null;
46+
4247
export type PendingSuspenseBoundaries = Map<OffscreenInstance, SuspenseInfo>;
4348

4449
export function processTransitionCallbacks(

0 commit comments

Comments
 (0)