Skip to content

Commit 8d0987b

Browse files
committed
tracing markers
1 parent 7a5b822 commit 8d0987b

8 files changed

+463
-46
lines changed

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

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import type {
3535
} from './ReactFiberCacheComponent.new';
3636
import type {UpdateQueue} from './ReactUpdateQueue.new';
3737
import type {RootState} from './ReactFiberRoot.new';
38+
import type {TracingMarkerState} from './ReactFiberTracingMarkerComponent.new';
3839
import {
3940
enableSuspenseAvoidThisFallback,
4041
enableCPUSuspense,
@@ -253,6 +254,10 @@ import {
253254
getOffscreenDeferredCache,
254255
getSuspendedTransitions,
255256
} from './ReactFiberTransition.new';
257+
import {
258+
getTracingMarkers,
259+
pushTracingMarker,
260+
} from './ReactFiberTracingMarkerComponent.new';
256261

257262
const ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner;
258263

@@ -774,8 +779,11 @@ function updateOffscreenComponent(
774779
prevCachePool = prevState.cachePool;
775780
}
776781

777-
pushTransition(workInProgress, prevCachePool, null);
778-
782+
pushTransition(
783+
workInProgress,
784+
prevCachePool,
785+
workInProgress.memoizedState.transitions,
786+
);
779787
// Since we're not hidden anymore, reset the state
780788
workInProgress.memoizedState = null;
781789
} else {
@@ -882,6 +890,26 @@ function updateTracingMarkerComponent(
882890
return null;
883891
}
884892

893+
// Only update the tracing marker if it's newly rendered or it's name changed.
894+
// A tracing marker is only associated with the transitions that rendered
895+
// or updated it, so we can create a new set of transitions each time
896+
const updateMarker =
897+
current === null || current.memoizedProps !== workInProgress.pendingProps;
898+
if (updateMarker || !workInProgress.memoizedState) {
899+
const currentTransitions = getSuspendedTransitions();
900+
if (currentTransitions !== null) {
901+
const memoizedState: TracingMarkerState = {
902+
transitions: currentTransitions,
903+
pendingSuspenseBoundaries: new Map(),
904+
};
905+
workInProgress.memoizedState = memoizedState;
906+
} else {
907+
// If the marker was updated, all previous transitions on it are canceled
908+
workInProgress.memoizedState = null;
909+
}
910+
}
911+
912+
pushTracingMarker(workInProgress);
885913
const nextChildren = workInProgress.pendingProps.children;
886914
reconcileChildren(current, workInProgress, nextChildren, renderLanes);
887915
return workInProgress.child;
@@ -2085,8 +2113,12 @@ function updateSuspenseComponent(current, workInProgress, renderLanes) {
20852113
if (enableTransitionTracing) {
20862114
const currentTransitions = getSuspendedTransitions();
20872115
if (currentTransitions !== null) {
2116+
// If there are no transitions, we don't need to keep track of tracing markers
2117+
const currentTracingMarkers = getTracingMarkers();
20882118
const primaryChildUpdateQueue: OffscreenQueue = {
20892119
transitions: currentTransitions,
2120+
tracingMarkers: currentTracingMarkers,
2121+
markerSuspenseBoundaries: null,
20902122
};
20912123
primaryChildFragment.updateQueue = primaryChildUpdateQueue;
20922124
}
@@ -2162,15 +2194,23 @@ function updateSuspenseComponent(current, workInProgress, renderLanes) {
21622194
const primaryChildFragment: Fiber = (workInProgress.child: any);
21632195
const prevOffscreenState: OffscreenState | null = (current.child: any)
21642196
.memoizedState;
2197+
const prevUpdateQueue: OffscreenQueue | null = (current.child: any)
2198+
.memoizedState;
21652199
primaryChildFragment.memoizedState =
21662200
prevOffscreenState === null
21672201
? mountSuspenseOffscreenState(renderLanes)
21682202
: updateSuspenseOffscreenState(prevOffscreenState, renderLanes);
21692203
if (enableTransitionTracing) {
21702204
const currentTransitions = getSuspendedTransitions();
21712205
if (currentTransitions !== null) {
2206+
const currentTracingMarkers = getTracingMarkers();
21722207
const primaryChildUpdateQueue: OffscreenQueue = {
21732208
transitions: currentTransitions,
2209+
tracingMarkers: currentTracingMarkers,
2210+
markerSuspenseBoundaries:
2211+
prevUpdateQueue === null
2212+
? null
2213+
: prevUpdateQueue.markerSuspenseBoundaries,
21742214
};
21752215
primaryChildFragment.updateQueue = primaryChildUpdateQueue;
21762216
}
@@ -3645,6 +3685,11 @@ function attemptEarlyBailoutIfNoScheduledUpdate(
36453685
}
36463686
break;
36473687
}
3688+
case TracingMarkerComponent: {
3689+
if (enableTransitionTracing) {
3690+
pushTracingMarker(workInProgress);
3691+
}
3692+
}
36483693
}
36493694
return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);
36503695
}

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

Lines changed: 88 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,10 @@ import type {
2929
import type {HookFlags} from './ReactHookEffectTags';
3030
import type {Cache} from './ReactFiberCacheComponent.new';
3131
import type {RootState} from './ReactFiberRoot.new';
32-
import type {Transition} from './ReactFiberTracingMarkerComponent.new';
32+
import type {
33+
Transition,
34+
TracingMarkerState,
35+
} from './ReactFiberTracingMarkerComponent.new';
3336

3437
import {
3538
enableCreateEventHandleAPI,
@@ -139,6 +142,7 @@ import {
139142
restorePendingUpdaters,
140143
addTransitionStartCallbackToPendingTransition,
141144
addTransitionCompleteCallbackToPendingTransition,
145+
addMarkerCompleteCallbackToPendingTransition,
142146
setIsRunningInsertionEffect,
143147
} from './ReactFiberWorkLoop.new';
144148
import {
@@ -1073,6 +1077,7 @@ function reappearLayoutEffectsOnFiber(node: Fiber) {
10731077

10741078
function commitTransitionProgress(
10751079
finishedRoot: FiberRoot,
1080+
suspenseBoundaries: Array<PendingSuspenseBoundaries> | null,
10761081
offscreenFiber: Fiber,
10771082
) {
10781083
if (enableTransitionTracing) {
@@ -1118,35 +1123,42 @@ function commitTransitionProgress(
11181123
}
11191124

11201125
if (rootPendingBoundaries !== null) {
1121-
if (previousFiber === null) {
1122-
// Initial mount
1123-
if (isHidden) {
1124-
rootPendingBoundaries.set(offscreenInstance, {
1125-
name,
1126+
// Initial mount or hide
1127+
if (!wasHidden && isHidden) {
1128+
if (suspenseBoundaries !== null) {
1129+
suspenseBoundaries.forEach(pendingBoundaries => {
1130+
pendingBoundaries.set(offscreenInstance, {
1131+
name,
1132+
});
11261133
});
11271134
}
1128-
} else {
1129-
if (wasHidden && !isHidden) {
1130-
// The suspense boundary went from hidden to visible. Remove
1131-
// the boundary from the pending suspense boundaries set
1132-
// if it's there
1133-
if (rootPendingBoundaries.has(offscreenInstance)) {
1134-
rootPendingBoundaries.delete(offscreenInstance);
1135-
1136-
if (rootPendingBoundaries.size === 0 && rootTransitions !== null) {
1137-
rootTransitions.forEach(transition => {
1138-
addTransitionCompleteCallbackToPendingTransition({
1139-
transitionName: transition.name,
1140-
startTime: transition.startTime,
1141-
});
1135+
// The suspense boundaries was just hidden. Add the boundary
1136+
// to the pending boundary set if it's there
1137+
rootPendingBoundaries.set(offscreenInstance, {
1138+
name,
1139+
});
1140+
} else if (wasHidden && !isHidden) {
1141+
// The suspense boundary went from hidden to visible. Remove
1142+
// the boundary from the pending suspense boundaries set
1143+
// if it's there
1144+
if (rootPendingBoundaries.has(offscreenInstance)) {
1145+
rootPendingBoundaries.delete(offscreenInstance);
1146+
1147+
if (rootPendingBoundaries.size === 0 && rootTransitions !== null) {
1148+
rootTransitions.forEach(transition => {
1149+
addTransitionCompleteCallbackToPendingTransition({
1150+
transitionName: transition.name,
1151+
startTime: transition.startTime,
11421152
});
1143-
}
1153+
});
11441154
}
1145-
} else if (!wasHidden && isHidden) {
1146-
// The suspense boundaries was just hidden. Add the boundary
1147-
// to the pending boundary set if it's there
1148-
rootPendingBoundaries.set(offscreenInstance, {
1149-
name,
1155+
}
1156+
1157+
if (suspenseBoundaries !== null) {
1158+
suspenseBoundaries.forEach(pendingBoundaries => {
1159+
if (pendingBoundaries.has(offscreenInstance)) {
1160+
pendingBoundaries.delete(offscreenInstance);
1161+
}
11501162
});
11511163
}
11521164
}
@@ -2914,11 +2926,13 @@ function commitPassiveMountOnFiber(
29142926
}
29152927

29162928
if (enableTransitionTracing) {
2929+
let suspenseMarkers = null;
29172930
const isFallback = finishedWork.memoizedState;
29182931
const queue = (finishedWork.updateQueue: any);
29192932
const rootMemoizedState = finishedRoot.current.memoizedState;
29202933

29212934
if (queue !== null) {
2935+
suspenseMarkers = queue.markerSuspenseBoundaries;
29222936
// We have one instance of the pendingSuspenseBoundaries map.
29232937
// We only need one because we update it during the commit phase.
29242938
// We instantiate a new Map if we haven't already
@@ -2944,12 +2958,39 @@ function commitPassiveMountOnFiber(
29442958
prevTransitions.add(transition);
29452959
});
29462960
}
2961+
const tracingMarkers = queue.tracingMarkers;
2962+
2963+
if (tracingMarkers !== null) {
2964+
if (suspenseMarkers === null) {
2965+
queue.markerSuspenseBoundaries = suspenseMarkers = new Set();
2966+
}
2967+
tracingMarkers.forEach(marker => {
2968+
const markerTransitions = marker.memoizedState.transitions;
2969+
2970+
// There should only be a few tracing marker transitions because
2971+
// they should be only associated with the transition that
2972+
// caused them
2973+
markerTransitions.forEach(transition => {
2974+
if (finishedWork.memoizedState.transitions.has(transition)) {
2975+
suspenseMarkers.add(
2976+
marker.memoizedState.pendingSuspenseBoundaries,
2977+
);
2978+
}
2979+
});
2980+
});
2981+
}
29472982
}
29482983
}
29492984

2950-
commitTransitionProgress(finishedRoot, finishedWork);
2985+
commitTransitionProgress(finishedRoot, suspenseMarkers, finishedWork);
29512986

2952-
finishedWork.updateQueue = null;
2987+
if (
2988+
queue === null ||
2989+
queue.markerSuspenseBoundaries === null ||
2990+
queue.markerSuspenseBoundaries.size === 0
2991+
) {
2992+
finishedWork.updateQueue = null;
2993+
}
29532994
}
29542995

29552996
break;
@@ -2975,6 +3016,25 @@ function commitPassiveMountOnFiber(
29753016
}
29763017
break;
29773018
}
3019+
case TracingMarkerComponent: {
3020+
if (enableTransitionTracing) {
3021+
// Get the transitions that were initiatized during the render
3022+
// and add a start transition callback for each of them
3023+
const state = finishedWork.memoizedState;
3024+
if (state !== null && state.pendingSuspenseBoundaries.size === 0) {
3025+
state.transitions.forEach(transition => {
3026+
addMarkerCompleteCallbackToPendingTransition({
3027+
transitionName: transition.name,
3028+
startTime: transition.startTime,
3029+
markerName: finishedWork.memoizedProps.name,
3030+
});
3031+
});
3032+
3033+
finishedWork.memoizedState = null;
3034+
}
3035+
}
3036+
break;
3037+
}
29783038
}
29793039
}
29803040

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ import {transferActualDuration} from './ReactProfilerTimer.new';
165165
import {popCacheProvider} from './ReactFiberCacheComponent.new';
166166
import {popTreeContext} from './ReactFiberTreeContext.new';
167167
import {popRootTransition, popTransition} from './ReactFiberTransition.new';
168+
import {popTracingMarker} from './ReactFiberTracingMarkerComponent.new';
168169

169170
function markUpdate(workInProgress: Fiber) {
170171
// Tag the fiber with an update effect. This turns a Placement into
@@ -1585,7 +1586,23 @@ function completeWork(
15851586
case TracingMarkerComponent: {
15861587
if (enableTransitionTracing) {
15871588
// Bubble subtree flags before so we can set the flag property
1589+
const updateMarker =
1590+
current === null ||
1591+
current.memoizedProps !== workInProgress.pendingProps;
1592+
if (updateMarker) {
1593+
workInProgress.flags |= Passive;
1594+
}
1595+
popTracingMarker(workInProgress);
15881596
bubbleProperties(workInProgress);
1597+
1598+
if (enableTransitionTracing) {
1599+
if ((workInProgress.subtreeFlags & Visibility) !== NoFlags) {
1600+
// If any of our suspense children toggle visibility, this means that
1601+
// the pending boundaries array needs to be updated, which we only
1602+
// do in the passive phase.
1603+
workInProgress.flags |= Passive;
1604+
}
1605+
}
15891606
}
15901607
return null;
15911608
}

packages/react-reconciler/src/ReactFiberOffscreenComponent.js

Lines changed: 3 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 {Transition} from './ReactFiberTracingMarkerComponent.new';
@@ -36,6 +37,8 @@ export type OffscreenState = {|
3637

3738
export type OffscreenQueue = {|
3839
transitions: Array<Transition> | null,
40+
tracingMarkers: Array<Fiber> | null,
41+
markerSuspenseBoundaries: Set<PendingSuspenseBoundaries> | null,
3942
|} | null;
4043

4144
export type OffscreenInstance = {};

0 commit comments

Comments
 (0)