@@ -30,7 +30,11 @@ import type {
3030import type { HookFlags } from './ReactHookEffectTags' ;
3131import type { Cache } from './ReactFiberCacheComponent.old' ;
3232import type { RootState } from './ReactFiberRoot.old' ;
33- import type { Transition } from './ReactFiberTracingMarkerComponent.old' ;
33+ import type {
34+ Transition ,
35+ TracingMarkerInstance ,
36+ TransitionAbort ,
37+ } from './ReactFiberTracingMarkerComponent.old' ;
3438
3539import {
3640 enableCreateEventHandleAPI ,
@@ -146,6 +150,7 @@ import {
146150 addTransitionProgressCallbackToPendingTransition ,
147151 addTransitionCompleteCallbackToPendingTransition ,
148152 addMarkerProgressCallbackToPendingTransition ,
153+ addMarkerIncompleteCallbackToPendingTransition ,
149154 addMarkerCompleteCallbackToPendingTransition ,
150155 setIsRunningInsertionEffect ,
151156} from './ReactFiberWorkLoop.old' ;
@@ -1135,6 +1140,128 @@ function commitLayoutEffectOnFiber(
11351140 }
11361141}
11371142
1143+ function abortTransitionMarker (
1144+ deletedFiber : Fiber ,
1145+ currentFiber : Fiber ,
1146+ abort : TransitionAbort ,
1147+ isInDeletedTree : boolean ,
1148+ ) {
1149+ const markerInstance : TracingMarkerInstance = currentFiber . stateNode ;
1150+ const deletedInstance : OffscreenInstance = deletedFiber . stateNode ;
1151+ const deletedTransitions = deletedFiber . stateNode . transitions ;
1152+ const pendingBoundaries = markerInstance . pendingBoundaries ;
1153+
1154+ let aborts = markerInstance . aborts ;
1155+ if ( aborts === null ) {
1156+ markerInstance . aborts = aborts = [ ] ;
1157+ }
1158+
1159+ aborts . push ( abort ) ;
1160+ addMarkerIncompleteCallbackToPendingTransition (
1161+ currentFiber . memoizedProps . name ,
1162+ deletedTransitions ,
1163+ aborts ,
1164+ ) ;
1165+
1166+ // We only want to call onTransitionProgress when the marker hasn't been
1167+ // deleted
1168+ if (
1169+ ! isInDeletedTree &&
1170+ pendingBoundaries !== null &&
1171+ pendingBoundaries . has ( deletedInstance )
1172+ ) {
1173+ pendingBoundaries . delete ( deletedInstance ) ;
1174+
1175+ addMarkerProgressCallbackToPendingTransition (
1176+ currentFiber . memoizedProps . name ,
1177+ deletedTransitions ,
1178+ pendingBoundaries ,
1179+ ) ;
1180+ }
1181+ }
1182+
1183+ function abortParentMarkerTransitions (
1184+ deletedFiber : Fiber ,
1185+ nearestMountedAncestor : Fiber ,
1186+ abort : TransitionAbort ,
1187+ ) {
1188+ // Find all pending markers that are waiting on child suspense boundaries in the
1189+ // aborted subtree and cancels them
1190+ const deletedFiberInstance : OffscreenInstance = deletedFiber . stateNode ;
1191+ const abortedTransitions = deletedFiberInstance . transitions ;
1192+ if ( abortedTransitions !== null ) {
1193+ let fiber = deletedFiber ;
1194+ let isInDeletedTree = true ;
1195+ while ( fiber !== null ) {
1196+ switch ( fiber . tag ) {
1197+ case TracingMarkerComponent :
1198+ const markerInstance : TracingMarkerInstance = fiber . stateNode ;
1199+ const markerTransitions = markerInstance . transitions ;
1200+ if ( markerTransitions !== null ) {
1201+ // TODO: Refactor this code. Is there a way to move this code to
1202+ // the deletions phase instead of calculating it here while making sure
1203+ // complete is called appropriately?
1204+ abortedTransitions . forEach ( transition => {
1205+ // If one of the transitions on the tracing marker is a transition
1206+ // that was in an aborted subtree, we will abort that tracing marker
1207+ if (
1208+ fiber !== null &&
1209+ markerTransitions . has ( transition ) &&
1210+ ( markerInstance . aborts === null ||
1211+ ! markerInstance . aborts . includes ( abort ) )
1212+ ) {
1213+ abortTransitionMarker (
1214+ deletedFiber ,
1215+ fiber ,
1216+ abort ,
1217+ isInDeletedTree ,
1218+ ) ;
1219+ }
1220+ } ) ;
1221+ }
1222+ break ;
1223+ case HostRoot :
1224+ const root = fiber . stateNode ;
1225+ const rootTransitions = root . incompleteTransitions ;
1226+
1227+ abortedTransitions . forEach ( transition => {
1228+ if ( rootTransitions . has ( transition ) ) {
1229+ const transitionInstance : TracingMarkerInstance = rootTransitions . get (
1230+ transition ,
1231+ ) ;
1232+ if ( transitionInstance . aborts === null ) {
1233+ transitionInstance . aborts = [ ] ;
1234+ }
1235+ transitionInstance . aborts . push ( abort ) ;
1236+
1237+ if (
1238+ transitionInstance . pendingBoundaries !== null &&
1239+ transitionInstance . pendingBoundaries . has ( deletedFiberInstance )
1240+ ) {
1241+ transitionInstance . pendingBoundaries . delete (
1242+ deletedFiberInstance ,
1243+ ) ;
1244+ }
1245+ }
1246+ } ) ;
1247+ break ;
1248+ default :
1249+ break ;
1250+ }
1251+
1252+ if (
1253+ nearestMountedAncestor . deletions !== null &&
1254+ nearestMountedAncestor . deletions . includes ( fiber )
1255+ ) {
1256+ isInDeletedTree = false ;
1257+ fiber = nearestMountedAncestor ;
1258+ } else {
1259+ fiber = fiber . return ;
1260+ }
1261+ }
1262+ }
1263+ }
1264+
11381265function commitTransitionProgress ( offscreenFiber : Fiber ) {
11391266 if ( enableTransitionTracing ) {
11401267 // This function adds suspense boundaries to the root
@@ -1180,6 +1307,7 @@ function commitTransitionProgress(offscreenFiber: Fiber) {
11801307 pendingMarkers . forEach ( markerInstance => {
11811308 const pendingBoundaries = markerInstance . pendingBoundaries ;
11821309 const transitions = markerInstance . transitions ;
1310+ const markerName = markerInstance . name ;
11831311 if (
11841312 pendingBoundaries !== null &&
11851313 ! pendingBoundaries . has ( offscreenInstance )
@@ -1190,10 +1318,10 @@ function commitTransitionProgress(offscreenFiber: Fiber) {
11901318 if ( transitions !== null ) {
11911319 if (
11921320 markerInstance . tag === TransitionTracingMarker &&
1193- markerInstance . name !== undefined
1321+ markerName !== null
11941322 ) {
11951323 addMarkerProgressCallbackToPendingTransition (
1196- markerInstance . name ,
1324+ markerName ,
11971325 transitions ,
11981326 pendingBoundaries ,
11991327 ) ;
@@ -1217,6 +1345,7 @@ function commitTransitionProgress(offscreenFiber: Fiber) {
12171345 pendingMarkers . forEach ( markerInstance => {
12181346 const pendingBoundaries = markerInstance . pendingBoundaries ;
12191347 const transitions = markerInstance . transitions ;
1348+ const markerName = markerInstance . name ;
12201349 if (
12211350 pendingBoundaries !== null &&
12221351 pendingBoundaries . has ( offscreenInstance )
@@ -1225,13 +1354,25 @@ function commitTransitionProgress(offscreenFiber: Fiber) {
12251354 if ( transitions !== null ) {
12261355 if (
12271356 markerInstance . tag === TransitionTracingMarker &&
1228- markerInstance . name !== undefined
1357+ markerName !== null
12291358 ) {
12301359 addMarkerProgressCallbackToPendingTransition (
1231- markerInstance . name ,
1360+ markerName ,
12321361 transitions ,
12331362 pendingBoundaries ,
12341363 ) ;
1364+
1365+ if ( pendingBoundaries . size === 0 ) {
1366+ if ( markerInstance . aborts === null ) {
1367+ addMarkerCompleteCallbackToPendingTransition (
1368+ markerName ,
1369+ transitions ,
1370+ ) ;
1371+ }
1372+ markerInstance . transitions = null ;
1373+ markerInstance . pendingBoundaries = null ;
1374+ markerInstance . aborts = null ;
1375+ }
12351376 } else if ( markerInstance . tag === TransitionRoot ) {
12361377 transitions . forEach ( transition => {
12371378 addTransitionProgressCallbackToPendingTransition (
@@ -1996,6 +2137,7 @@ function commitDeletionEffectsOnFiber(
19962137 const prevOffscreenSubtreeWasHidden = offscreenSubtreeWasHidden ;
19972138 offscreenSubtreeWasHidden =
19982139 prevOffscreenSubtreeWasHidden || deletedFiber . memoizedState !== null ;
2140+
19992141 recursivelyTraverseDeletionEffects (
20002142 finishedRoot ,
20012143 nearestMountedAncestor ,
@@ -2011,6 +2153,45 @@ function commitDeletionEffectsOnFiber(
20112153 }
20122154 break ;
20132155 }
2156+ case SuspenseComponent : {
2157+ if ( enableTransitionTracing ) {
2158+ // We need to mark this fiber's parents as deleted
2159+ const offscreenFiber : Fiber = ( deletedFiber . child : any ) ;
2160+ const instance : OffscreenInstance = offscreenFiber . stateNode ;
2161+ const transitions = instance . transitions ;
2162+ if ( transitions !== null ) {
2163+ abortParentMarkerTransitions ( offscreenFiber , nearestMountedAncestor , {
2164+ reason : 'suspense' ,
2165+ name : deletedFiber . memoizedProps . unstable_name || null ,
2166+ } ) ;
2167+ }
2168+ }
2169+ recursivelyTraverseDeletionEffects (
2170+ finishedRoot ,
2171+ nearestMountedAncestor ,
2172+ deletedFiber ,
2173+ ) ;
2174+ return ;
2175+ }
2176+ case TracingMarkerComponent : {
2177+ if ( enableTransitionTracing ) {
2178+ // We need to mark this fiber's parents as deleted
2179+ const instance : TracingMarkerInstance = deletedFiber . stateNode ;
2180+ const transitions = instance . transitions ;
2181+ if ( transitions !== null ) {
2182+ abortParentMarkerTransitions ( deletedFiber , nearestMountedAncestor , {
2183+ reason : 'marker' ,
2184+ name : deletedFiber . memoizedProps . name ,
2185+ } ) ;
2186+ }
2187+ }
2188+ recursivelyTraverseDeletionEffects (
2189+ finishedRoot ,
2190+ nearestMountedAncestor ,
2191+ deletedFiber ,
2192+ ) ;
2193+ return ;
2194+ }
20142195 default : {
20152196 recursivelyTraverseDeletionEffects (
20162197 finishedRoot ,
@@ -2986,6 +3167,12 @@ function commitOffscreenPassiveMountEffects(
29863167 }
29873168
29883169 commitTransitionProgress ( finishedWork ) ;
3170+
3171+ // TODO: Refactor this into an if/else branch
3172+ if ( ! isHidden ) {
3173+ instance . transitions = null ;
3174+ instance . pendingMarkers = null ;
3175+ }
29893176 }
29903177}
29913178
@@ -3016,20 +3203,18 @@ function commitCachePassiveMountEffect(
30163203function commitTracingMarkerPassiveMountEffect ( finishedWork : Fiber ) {
30173204 // Get the transitions that were initiatized during the render
30183205 // and add a start transition callback for each of them
3206+ // We will only call this on initial mount of the tracing marker
3207+ // only if there are no suspense children
30193208 const instance = finishedWork . stateNode ;
3020- if (
3021- instance . transitions !== null &&
3022- ( instance . pendingBoundaries === null ||
3023- instance . pendingBoundaries . size === 0 )
3024- ) {
3025- instance . transitions . forEach ( transition => {
3026- addMarkerCompleteCallbackToPendingTransition (
3027- finishedWork . memoizedProps . name ,
3028- instance . transitions ,
3029- ) ;
3030- } ) ;
3209+ if ( instance . transitions !== null && instance . pendingBoundaries === null ) {
3210+ addMarkerCompleteCallbackToPendingTransition (
3211+ finishedWork . memoizedProps . name ,
3212+ instance . transitions ,
3213+ ) ;
30313214 instance . transitions = null ;
30323215 instance . pendingBoundaries = null ;
3216+ instance . aborts = null ;
3217+ instance . name = null ;
30333218 }
30343219}
30353220
@@ -3145,7 +3330,9 @@ function commitPassiveMountOnFiber(
31453330 incompleteTransitions . forEach ( ( markerInstance , transition ) => {
31463331 const pendingBoundaries = markerInstance . pendingBoundaries ;
31473332 if ( pendingBoundaries === null || pendingBoundaries . size === 0 ) {
3148- addTransitionCompleteCallbackToPendingTransition ( transition ) ;
3333+ if ( markerInstance . aborts === null ) {
3334+ addTransitionCompleteCallbackToPendingTransition ( transition ) ;
3335+ }
31493336 incompleteTransitions . delete ( transition ) ;
31503337 }
31513338 } ) ;
@@ -3518,21 +3705,6 @@ function commitAtomicPassiveEffects(
35183705 }
35193706 break ;
35203707 }
3521- case TracingMarkerComponent : {
3522- if ( enableTransitionTracing ) {
3523- recursivelyTraverseAtomicPassiveEffects (
3524- finishedRoot ,
3525- finishedWork ,
3526- committedLanes ,
3527- committedTransitions ,
3528- ) ;
3529- if ( flags & Passive ) {
3530- commitTracingMarkerPassiveMountEffect ( finishedWork ) ;
3531- }
3532- break ;
3533- }
3534- // Intentional fallthrough to next branch
3535- }
35363708 // eslint-disable-next-line-no-fallthrough
35373709 default : {
35383710 recursivelyTraverseAtomicPassiveEffects (
0 commit comments