@@ -72,7 +72,9 @@ import {
72
72
NoFlags ,
73
73
DidCapture ,
74
74
Snapshot ,
75
+ ChildDeletion ,
75
76
StaticMask ,
77
+ MutationMask ,
76
78
} from './ReactFiberFlags' ;
77
79
import invariant from 'shared/invariant' ;
78
80
@@ -173,6 +175,31 @@ function markRef(workInProgress: Fiber) {
173
175
workInProgress . flags |= Ref ;
174
176
}
175
177
178
+ function hadNoMutationsEffects ( current : null | Fiber , completedWork : Fiber ) {
179
+ const didBailout = current !== null && current . child === completedWork . child ;
180
+ if ( didBailout ) {
181
+ return true ;
182
+ }
183
+
184
+ if ( ( completedWork . flags & ChildDeletion ) !== NoFlags ) {
185
+ return false ;
186
+ }
187
+
188
+ // TODO: If we move the `hadNoMutationsEffects` call after `bubbleProperties`
189
+ // then we only have to check the `completedWork.subtreeFlags`.
190
+ let child = completedWork . child ;
191
+ while ( child !== null ) {
192
+ if (
193
+ ( child . flags & MutationMask ) !== NoFlags ||
194
+ ( child . subtreeFlags & MutationMask ) !== NoFlags
195
+ ) {
196
+ return false ;
197
+ }
198
+ child = child . sibling ;
199
+ }
200
+ return true ;
201
+ }
202
+
176
203
let appendAllChildren ;
177
204
let updateHostContainer ;
178
205
let updateHostComponent ;
@@ -217,7 +244,7 @@ if (supportsMutation) {
217
244
}
218
245
} ;
219
246
220
- updateHostContainer = function ( workInProgress : Fiber ) {
247
+ updateHostContainer = function ( current : null | Fiber , workInProgress : Fiber ) {
221
248
// Noop
222
249
} ;
223
250
updateHostComponent = function (
@@ -461,13 +488,13 @@ if (supportsMutation) {
461
488
node = node . sibling ;
462
489
}
463
490
} ;
464
- updateHostContainer = function ( workInProgress : Fiber ) {
491
+ updateHostContainer = function ( current : null | Fiber , workInProgress : Fiber ) {
465
492
const portalOrRoot : {
466
493
containerInfo : Container ,
467
494
pendingChildren : ChildSet ,
468
495
...
469
496
} = workInProgress . stateNode ;
470
- const childrenUnchanged = workInProgress . firstEffect === null ;
497
+ const childrenUnchanged = hadNoMutationsEffects ( current , workInProgress ) ;
471
498
if ( childrenUnchanged ) {
472
499
// No changes, just reuse the existing instance.
473
500
} else {
@@ -492,7 +519,7 @@ if (supportsMutation) {
492
519
const oldProps = current . memoizedProps ;
493
520
// If there are no effects associated with this node, then none of our children had any updates.
494
521
// This guarantees that we can reuse all of them.
495
- const childrenUnchanged = workInProgress . firstEffect === null ;
522
+ const childrenUnchanged = hadNoMutationsEffects ( current , workInProgress ) ;
496
523
if ( childrenUnchanged && oldProps === newProps ) {
497
524
// No changes, just reuse the existing instance.
498
525
// Note that this might release a previous clone.
@@ -575,7 +602,7 @@ if (supportsMutation) {
575
602
} ;
576
603
} else {
577
604
// No host operations
578
- updateHostContainer = function ( workInProgress : Fiber ) {
605
+ updateHostContainer = function ( current : null | Fiber , workInProgress : Fiber ) {
579
606
// Noop
580
607
} ;
581
608
updateHostComponent = function (
@@ -847,7 +874,7 @@ function completeWork(
847
874
workInProgress . flags |= Snapshot ;
848
875
}
849
876
}
850
- updateHostContainer ( workInProgress ) ;
877
+ updateHostContainer ( current , workInProgress ) ;
851
878
bubbleProperties ( workInProgress ) ;
852
879
return null ;
853
880
}
@@ -1142,7 +1169,7 @@ function completeWork(
1142
1169
}
1143
1170
case HostPortal :
1144
1171
popHostContainer ( workInProgress ) ;
1145
- updateHostContainer ( workInProgress ) ;
1172
+ updateHostContainer ( current , workInProgress ) ;
1146
1173
if ( current === null ) {
1147
1174
preparePortalMount ( workInProgress . stateNode . containerInfo ) ;
1148
1175
}
@@ -1226,11 +1253,7 @@ function completeWork(
1226
1253
1227
1254
// Rerender the whole list, but this time, we'll force fallbacks
1228
1255
// to stay in place.
1229
- // Reset the effect list before doing the second pass since that's now invalid.
1230
- if ( renderState . lastEffect === null ) {
1231
- workInProgress . firstEffect = null ;
1232
- }
1233
- workInProgress . lastEffect = renderState . lastEffect ;
1256
+ // Reset the effect flags before doing the second pass since that's now invalid.
1234
1257
// Reset the child fibers to their original state.
1235
1258
workInProgress . subtreeFlags = NoFlags ;
1236
1259
resetChildFibers ( workInProgress , renderLanes ) ;
@@ -1301,15 +1324,6 @@ function completeWork(
1301
1324
! renderedTail . alternate &&
1302
1325
! getIsHydrating ( ) // We don't cut it if we're hydrating.
1303
1326
) {
1304
- // We need to delete the row we just rendered.
1305
- // Reset the effect list to what it was before we rendered this
1306
- // child. The nested children have already appended themselves.
1307
- const lastEffect = ( workInProgress . lastEffect =
1308
- renderState . lastEffect ) ;
1309
- // Remove any effects that were appended after this point.
1310
- if ( lastEffect !== null ) {
1311
- lastEffect . nextEffect = null ;
1312
- }
1313
1327
// We're done.
1314
1328
bubbleProperties ( workInProgress ) ;
1315
1329
return null ;
@@ -1369,7 +1383,6 @@ function completeWork(
1369
1383
const next = renderState . tail ;
1370
1384
renderState . rendering = next ;
1371
1385
renderState . tail = next . sibling ;
1372
- renderState . lastEffect = workInProgress . lastEffect ;
1373
1386
renderState . renderingStartTime = now ( ) ;
1374
1387
next . sibling = null ;
1375
1388
0 commit comments