@@ -68,6 +68,8 @@ import {
68
68
Placement ,
69
69
Snapshot ,
70
70
Update ,
71
+ Passive ,
72
+ PassiveUnmountPendingDev ,
71
73
} from './ReactSideEffectTags' ;
72
74
import getComponentName from 'shared/getComponentName' ;
73
75
import invariant from 'shared/invariant' ;
@@ -115,9 +117,8 @@ import {
115
117
captureCommitPhaseError ,
116
118
resolveRetryWakeable ,
117
119
markCommitTimeOfFallback ,
118
- enqueuePendingPassiveHookEffectMount ,
119
- enqueuePendingPassiveHookEffectUnmount ,
120
120
enqueuePendingPassiveProfilerEffect ,
121
+ schedulePassiveEffectCallback ,
121
122
} from './ReactFiberWorkLoop.new' ;
122
123
import {
123
124
NoEffect as NoHookEffect ,
@@ -130,6 +131,10 @@ import {
130
131
updateDeprecatedEventListeners ,
131
132
unmountDeprecatedResponderListeners ,
132
133
} from './ReactFiberDeprecatedEvents.new' ;
134
+ import {
135
+ NoEffect as NoSubtreeTag ,
136
+ Passive as PassiveSubtreeTag ,
137
+ } from './ReactSubtreeTags' ;
133
138
134
139
let didWarnAboutUndefinedSnapshotBeforeUpdate : Set < mixed > | null = null ;
135
140
if ( __DEV__ ) {
@@ -381,26 +386,6 @@ function commitHookEffectListMount(tag: number, finishedWork: Fiber) {
381
386
}
382
387
}
383
388
384
- function schedulePassiveEffects ( finishedWork : Fiber ) {
385
- const updateQueue : FunctionComponentUpdateQueue | null = ( finishedWork . updateQueue : any ) ;
386
- const lastEffect = updateQueue !== null ? updateQueue . lastEffect : null ;
387
- if ( lastEffect !== null ) {
388
- const firstEffect = lastEffect . next ;
389
- let effect = firstEffect ;
390
- do {
391
- const { next, tag} = effect ;
392
- if (
393
- ( tag & HookPassive ) !== NoHookEffect &&
394
- ( tag & HookHasEffect ) !== NoHookEffect
395
- ) {
396
- enqueuePendingPassiveHookEffectUnmount ( finishedWork , effect ) ;
397
- enqueuePendingPassiveHookEffectMount ( finishedWork , effect ) ;
398
- }
399
- effect = next ;
400
- } while ( effect !== firstEffect ) ;
401
- }
402
- }
403
-
404
389
export function commitPassiveEffectDurations (
405
390
finishedRoot : FiberRoot ,
406
391
finishedWork : Fiber ,
@@ -486,7 +471,9 @@ function commitLifeCycles(
486
471
commitHookEffectListMount ( HookLayout | HookHasEffect , finishedWork ) ;
487
472
}
488
473
489
- schedulePassiveEffects ( finishedWork ) ;
474
+ if ( ( finishedWork . subtreeTag & PassiveSubtreeTag ) !== NoSubtreeTag ) {
475
+ schedulePassiveEffectCallback ( ) ;
476
+ }
490
477
return ;
491
478
}
492
479
case ClassComponent : {
@@ -892,7 +879,35 @@ function commitUnmount(
892
879
const { destroy, tag} = effect ;
893
880
if ( destroy !== undefined ) {
894
881
if ( ( tag & HookPassive ) !== NoHookEffect ) {
895
- enqueuePendingPassiveHookEffectUnmount ( current , effect ) ;
882
+ effect . tag |= HookHasEffect ;
883
+
884
+ // subtreeTags bubble in resetChildLanes which doens't get called for unmounted subtrees.
885
+ // So in the case of unmounts, we need to bubble passive effects explicitly.
886
+ let ancestor = current . return ;
887
+ while ( ancestor !== null ) {
888
+ ancestor . subtreeTag |= PassiveSubtreeTag ;
889
+ const alternate = ancestor . alternate ;
890
+ if ( alternate !== null ) {
891
+ alternate . subtreeTag |= PassiveSubtreeTag ;
892
+ }
893
+
894
+ ancestor = ancestor . return ;
895
+ }
896
+
897
+ current . effectTag |= Passive ;
898
+
899
+ if ( __DEV__ ) {
900
+ // This flag is used to avoid warning about an update to an unmounted component
901
+ // if the component has a passive unmount scheduled.
902
+ // Presumably the listener would be cleaned up by that unmount.
903
+ current . effectTag |= PassiveUnmountPendingDev ;
904
+ const alternate = current . alternate ;
905
+ if ( alternate !== null ) {
906
+ alternate . effectTag |= PassiveUnmountPendingDev ;
907
+ }
908
+ }
909
+
910
+ schedulePassiveEffectCallback ( ) ;
896
911
} else {
897
912
if (
898
913
enableProfilerTimer &&
@@ -1013,8 +1028,11 @@ function commitNestedUnmounts(
1013
1028
}
1014
1029
1015
1030
function detachFiberMutation ( fiber : Fiber ) {
1016
- // Cut off the return pointers to disconnect it from the tree. Ideally, we
1017
- // should clear the child pointer of the parent alternate to let this
1031
+ // Cut off the return pointers to disconnect it from the tree.
1032
+ // Note that we can't clear child or sibling pointers yet,
1033
+ // because they may be required for passive effects.
1034
+ // These pointers will be cleared in a separate pass.
1035
+ // Ideally, we should clear the child pointer of the parent alternate to let this
1018
1036
// get GC:ed but we don't know which for sure which parent is the current
1019
1037
// one so we'll settle for GC:ing the subtree of this child. This child
1020
1038
// itself will be GC:ed when the parent updates the next time.
@@ -1023,7 +1041,6 @@ function detachFiberMutation(fiber: Fiber) {
1023
1041
// traversal in a later effect. See PR #16820. We now clear the sibling
1024
1042
// field after effects, see: detachFiberAfterEffects.
1025
1043
fiber . alternate = null ;
1026
- fiber . child = null ;
1027
1044
fiber . dependencies = null ;
1028
1045
fiber . firstEffect = null ;
1029
1046
fiber . lastEffect = null ;
@@ -1032,7 +1049,6 @@ function detachFiberMutation(fiber: Fiber) {
1032
1049
fiber . pendingProps = null ;
1033
1050
fiber . return = null ;
1034
1051
fiber . stateNode = null ;
1035
- fiber . updateQueue = null ;
1036
1052
if ( __DEV__ ) {
1037
1053
fiber . _debugOwner = null ;
1038
1054
}
0 commit comments