@@ -30,7 +30,11 @@ import type {
30
30
import type { HookFlags } from './ReactHookEffectTags' ;
31
31
import type { Cache } from './ReactFiberCacheComponent.old' ;
32
32
import 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' ;
34
38
35
39
import {
36
40
enableCreateEventHandleAPI ,
@@ -146,6 +150,7 @@ import {
146
150
addTransitionProgressCallbackToPendingTransition ,
147
151
addTransitionCompleteCallbackToPendingTransition ,
148
152
addMarkerProgressCallbackToPendingTransition ,
153
+ addMarkerIncompleteCallbackToPendingTransition ,
149
154
addMarkerCompleteCallbackToPendingTransition ,
150
155
setIsRunningInsertionEffect ,
151
156
} from './ReactFiberWorkLoop.old' ;
@@ -1135,6 +1140,128 @@ function commitLayoutEffectOnFiber(
1135
1140
}
1136
1141
}
1137
1142
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
+
1138
1265
function commitTransitionProgress ( offscreenFiber : Fiber ) {
1139
1266
if ( enableTransitionTracing ) {
1140
1267
// This function adds suspense boundaries to the root
@@ -1180,6 +1307,7 @@ function commitTransitionProgress(offscreenFiber: Fiber) {
1180
1307
pendingMarkers . forEach ( markerInstance => {
1181
1308
const pendingBoundaries = markerInstance . pendingBoundaries ;
1182
1309
const transitions = markerInstance . transitions ;
1310
+ const markerName = markerInstance . name ;
1183
1311
if (
1184
1312
pendingBoundaries !== null &&
1185
1313
! pendingBoundaries . has ( offscreenInstance )
@@ -1190,10 +1318,10 @@ function commitTransitionProgress(offscreenFiber: Fiber) {
1190
1318
if ( transitions !== null ) {
1191
1319
if (
1192
1320
markerInstance . tag === TransitionTracingMarker &&
1193
- markerInstance . name !== undefined
1321
+ markerName !== null
1194
1322
) {
1195
1323
addMarkerProgressCallbackToPendingTransition (
1196
- markerInstance . name ,
1324
+ markerName ,
1197
1325
transitions ,
1198
1326
pendingBoundaries ,
1199
1327
) ;
@@ -1217,6 +1345,7 @@ function commitTransitionProgress(offscreenFiber: Fiber) {
1217
1345
pendingMarkers . forEach ( markerInstance => {
1218
1346
const pendingBoundaries = markerInstance . pendingBoundaries ;
1219
1347
const transitions = markerInstance . transitions ;
1348
+ const markerName = markerInstance . name ;
1220
1349
if (
1221
1350
pendingBoundaries !== null &&
1222
1351
pendingBoundaries . has ( offscreenInstance )
@@ -1225,13 +1354,25 @@ function commitTransitionProgress(offscreenFiber: Fiber) {
1225
1354
if ( transitions !== null ) {
1226
1355
if (
1227
1356
markerInstance . tag === TransitionTracingMarker &&
1228
- markerInstance . name !== undefined
1357
+ markerName !== null
1229
1358
) {
1230
1359
addMarkerProgressCallbackToPendingTransition (
1231
- markerInstance . name ,
1360
+ markerName ,
1232
1361
transitions ,
1233
1362
pendingBoundaries ,
1234
1363
) ;
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
+ }
1235
1376
} else if ( markerInstance . tag === TransitionRoot ) {
1236
1377
transitions . forEach ( transition => {
1237
1378
addTransitionProgressCallbackToPendingTransition (
@@ -1996,6 +2137,7 @@ function commitDeletionEffectsOnFiber(
1996
2137
const prevOffscreenSubtreeWasHidden = offscreenSubtreeWasHidden ;
1997
2138
offscreenSubtreeWasHidden =
1998
2139
prevOffscreenSubtreeWasHidden || deletedFiber . memoizedState !== null ;
2140
+
1999
2141
recursivelyTraverseDeletionEffects (
2000
2142
finishedRoot ,
2001
2143
nearestMountedAncestor ,
@@ -2011,6 +2153,45 @@ function commitDeletionEffectsOnFiber(
2011
2153
}
2012
2154
break ;
2013
2155
}
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
+ }
2014
2195
default : {
2015
2196
recursivelyTraverseDeletionEffects (
2016
2197
finishedRoot ,
@@ -2986,6 +3167,12 @@ function commitOffscreenPassiveMountEffects(
2986
3167
}
2987
3168
2988
3169
commitTransitionProgress ( finishedWork ) ;
3170
+
3171
+ // TODO: Refactor this into an if/else branch
3172
+ if ( ! isHidden ) {
3173
+ instance . transitions = null ;
3174
+ instance . pendingMarkers = null ;
3175
+ }
2989
3176
}
2990
3177
}
2991
3178
@@ -3016,20 +3203,18 @@ function commitCachePassiveMountEffect(
3016
3203
function commitTracingMarkerPassiveMountEffect ( finishedWork : Fiber ) {
3017
3204
// Get the transitions that were initiatized during the render
3018
3205
// 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
3019
3208
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
+ ) ;
3031
3214
instance . transitions = null ;
3032
3215
instance . pendingBoundaries = null ;
3216
+ instance . aborts = null ;
3217
+ instance . name = null ;
3033
3218
}
3034
3219
}
3035
3220
@@ -3145,7 +3330,9 @@ function commitPassiveMountOnFiber(
3145
3330
incompleteTransitions . forEach ( ( markerInstance , transition ) => {
3146
3331
const pendingBoundaries = markerInstance . pendingBoundaries ;
3147
3332
if ( pendingBoundaries === null || pendingBoundaries . size === 0 ) {
3148
- addTransitionCompleteCallbackToPendingTransition ( transition ) ;
3333
+ if ( markerInstance . aborts === null ) {
3334
+ addTransitionCompleteCallbackToPendingTransition ( transition ) ;
3335
+ }
3149
3336
incompleteTransitions . delete ( transition ) ;
3150
3337
}
3151
3338
} ) ;
@@ -3518,21 +3705,6 @@ function commitAtomicPassiveEffects(
3518
3705
}
3519
3706
break ;
3520
3707
}
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
- }
3536
3708
// eslint-disable-next-line-no-fallthrough
3537
3709
default : {
3538
3710
recursivelyTraverseAtomicPassiveEffects (
0 commit comments