@@ -68,6 +68,7 @@ import {
68
68
Placement ,
69
69
Snapshot ,
70
70
Update ,
71
+ Passive ,
71
72
} from './ReactSideEffectTags' ;
72
73
import getComponentName from 'shared/getComponentName' ;
73
74
import invariant from 'shared/invariant' ;
@@ -115,9 +116,8 @@ import {
115
116
captureCommitPhaseError ,
116
117
resolveRetryWakeable ,
117
118
markCommitTimeOfFallback ,
118
- enqueuePendingPassiveHookEffectMount ,
119
- enqueuePendingPassiveHookEffectUnmount ,
120
119
enqueuePendingPassiveProfilerEffect ,
120
+ schedulePassiveEffectCallback ,
121
121
} from './ReactFiberWorkLoop.new' ;
122
122
import {
123
123
NoEffect as NoHookEffect ,
@@ -130,6 +130,10 @@ import {
130
130
updateDeprecatedEventListeners ,
131
131
unmountDeprecatedResponderListeners ,
132
132
} from './ReactFiberDeprecatedEvents.new' ;
133
+ import {
134
+ NoEffect as NoSubtreeTag ,
135
+ Passive as PassiveSubtreeTag ,
136
+ } from './ReactSubtreeTags' ;
133
137
134
138
let didWarnAboutUndefinedSnapshotBeforeUpdate : Set < mixed > | null = null ;
135
139
if ( __DEV__ ) {
@@ -381,26 +385,6 @@ function commitHookEffectListMount(tag: number, finishedWork: Fiber) {
381
385
}
382
386
}
383
387
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
388
export function commitPassiveEffectDurations (
405
389
finishedRoot : FiberRoot ,
406
390
finishedWork : Fiber ,
@@ -486,7 +470,9 @@ function commitLifeCycles(
486
470
commitHookEffectListMount ( HookLayout | HookHasEffect , finishedWork ) ;
487
471
}
488
472
489
- schedulePassiveEffects ( finishedWork ) ;
473
+ if ( ( finishedWork . subtreeTag & PassiveSubtreeTag ) !== NoSubtreeTag ) {
474
+ schedulePassiveEffectCallback ( ) ;
475
+ }
490
476
return ;
491
477
}
492
478
case ClassComponent : {
@@ -892,7 +878,12 @@ function commitUnmount(
892
878
const { destroy, tag} = effect ;
893
879
if ( destroy !== undefined ) {
894
880
if ( ( tag & HookPassive ) !== NoHookEffect ) {
895
- enqueuePendingPassiveHookEffectUnmount ( current , effect ) ;
881
+ // TODO: Consider if we can move this block out of the synchronous commit phase
882
+ effect . tag |= HookHasEffect ;
883
+
884
+ current . effectTag |= Passive ;
885
+
886
+ schedulePassiveEffectCallback ( ) ;
896
887
} else {
897
888
if (
898
889
enableProfilerTimer &&
@@ -1013,29 +1004,24 @@ function commitNestedUnmounts(
1013
1004
}
1014
1005
1015
1006
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
1007
+ // Cut off the return pointer to disconnect it from the tree.
1008
+ // This enables us to detect and warn against state updates on an unmounted component.
1009
+ // It also prevents events from bubbling from within disconnected components.
1010
+ //
1011
+ // Ideally, we should also clear the child pointer of the parent alternate to let this
1018
1012
// get GC:ed but we don't know which for sure which parent is the current
1019
- // one so we'll settle for GC:ing the subtree of this child. This child
1020
- // itself will be GC:ed when the parent updates the next time.
1021
- // Note: we cannot null out sibling here, otherwise it can cause issues
1022
- // with findDOMNode and how it requires the sibling field to carry out
1023
- // traversal in a later effect. See PR #16820. We now clear the sibling
1024
- // field after effects, see: detachFiberAfterEffects.
1025
- fiber . alternate = null ;
1026
- fiber . child = null ;
1027
- fiber . dependencies = null ;
1028
- fiber . firstEffect = null ;
1029
- fiber . lastEffect = null ;
1030
- fiber . memoizedProps = null ;
1031
- fiber . memoizedState = null ;
1032
- fiber . pendingProps = null ;
1033
- fiber . return = null ;
1034
- fiber . stateNode = null ;
1035
- fiber . updateQueue = null ;
1036
- if ( __DEV__ ) {
1037
- fiber . _debugOwner = null ;
1013
+ // one so we'll settle for GC:ing the subtree of this child.
1014
+ // This child itself will be GC:ed when the parent updates the next time.
1015
+ //
1016
+ // Note that we can't clear child or sibling pointers yet.
1017
+ // They're needed for passive effects and for findDOMNode.
1018
+ // We defer those fields, and all other cleanup, to the passive phase (see detachFiberAfterEffects).
1019
+ const alternate = fiber . alternate ;
1020
+ if ( alternate !== null ) {
1021
+ alternate . return = null ;
1022
+ fiber . alternate = null ;
1038
1023
}
1024
+ fiber . return = null ;
1039
1025
}
1040
1026
1041
1027
function emptyPortalContainer ( current : Fiber ) {
0 commit comments