@@ -15,6 +15,7 @@ import type {Interaction} from 'scheduler/src/Tracing';
15
15
import type { SuspenseState } from './ReactFiberSuspenseComponent.new' ;
16
16
import type { Effect as HookEffect } from './ReactFiberHooks.new' ;
17
17
import type { StackCursor } from './ReactFiberStack.new' ;
18
+ import type { FunctionComponentUpdateQueue } from './ReactFiberHooks.new' ;
18
19
19
20
import {
20
21
warnAboutDeprecatedLifecycles ,
@@ -50,6 +51,10 @@ import {
50
51
flushSyncCallbackQueue ,
51
52
scheduleSyncCallback ,
52
53
} from './SchedulerWithReactIntegration.new' ;
54
+ import {
55
+ NoFlags as NoHookEffect ,
56
+ Passive as HookPassive ,
57
+ } from './ReactHookEffectTags' ;
53
58
import {
54
59
logCommitStarted ,
55
60
logCommitStopped ,
@@ -127,7 +132,7 @@ import {
127
132
Snapshot ,
128
133
Callback ,
129
134
Passive ,
130
- PassiveUnmountPendingDev ,
135
+ PassiveStatic ,
131
136
Incomplete ,
132
137
HostEffectMask ,
133
138
Hydrating ,
@@ -194,6 +199,7 @@ import {
194
199
commitResetTextContent ,
195
200
isSuspenseBoundaryBeingHidden ,
196
201
commitPassiveMountEffects ,
202
+ commitPassiveUnmountEffects ,
197
203
detachFiberAfterEffects ,
198
204
} from './ReactFiberCommitWork.new' ;
199
205
import { enqueueUpdate } from './ReactUpdateQueue.new' ;
@@ -213,9 +219,7 @@ import {
213
219
import {
214
220
markNestedUpdateScheduled ,
215
221
recordCommitTime ,
216
- recordPassiveEffectDuration ,
217
222
resetNestedUpdateFlag ,
218
- startPassiveEffectTimer ,
219
223
startProfilerTimer ,
220
224
stopProfilerTimerIfRunningAndRecordDelta ,
221
225
syncNestedUpdateFlag ,
@@ -341,7 +345,6 @@ let rootDoesHavePassiveEffects: boolean = false;
341
345
let rootWithPendingPassiveEffects: FiberRoot | null = null;
342
346
let pendingPassiveEffectsRenderPriority: ReactPriorityLevel = NoSchedulerPriority;
343
347
let pendingPassiveEffectsLanes: Lanes = NoLanes;
344
- let pendingPassiveHookEffectsUnmount: Array< HookEffect | Fiber > = [];
345
348
let pendingPassiveProfilerEffects: Array< Fiber > = [];
346
349
347
350
let rootsWithPendingDiscreteUpdates: Set< FiberRoot > | null = null;
@@ -2499,14 +2502,6 @@ export function enqueuePendingPassiveHookEffectUnmount(
2499
2502
fiber : Fiber ,
2500
2503
effect : HookEffect ,
2501
2504
) : void {
2502
- pendingPassiveHookEffectsUnmount . push ( effect , fiber ) ;
2503
- if ( __DEV__ ) {
2504
- fiber . flags |= PassiveUnmountPendingDev ;
2505
- const alternate = fiber . alternate ;
2506
- if ( alternate !== null ) {
2507
- alternate . flags |= PassiveUnmountPendingDev ;
2508
- }
2509
- }
2510
2505
if ( ! rootDoesHavePassiveEffects ) {
2511
2506
rootDoesHavePassiveEffects = true ;
2512
2507
scheduleCallback ( NormalSchedulerPriority , ( ) => {
@@ -2549,74 +2544,7 @@ function flushPassiveEffectsImpl() {
2549
2544
executionContext |= CommitContext ;
2550
2545
const prevInteractions = pushInteractions ( root ) ;
2551
2546
2552
- // It's important that ALL pending passive effect destroy functions are called
2553
- // before ANY passive effect create functions are called.
2554
- // Otherwise effects in sibling components might interfere with each other.
2555
- // e.g. a destroy function in one component may unintentionally override a ref
2556
- // value set by a create function in another component.
2557
- // Layout effects have the same constraint.
2558
-
2559
- // First pass: Destroy stale passive effects.
2560
- const unmountEffects = pendingPassiveHookEffectsUnmount ;
2561
- pendingPassiveHookEffectsUnmount = [ ] ;
2562
- for ( let i = 0 ; i < unmountEffects . length ; i += 2 ) {
2563
- const effect = ( ( unmountEffects [ i ] : any ) : HookEffect ) ;
2564
- const fiber = ( ( unmountEffects [ i + 1 ] : any ) : Fiber ) ;
2565
- const destroy = effect . destroy ;
2566
- effect . destroy = undefined ;
2567
-
2568
- if ( __DEV__ ) {
2569
- fiber . flags &= ~ PassiveUnmountPendingDev ;
2570
- const alternate = fiber . alternate ;
2571
- if ( alternate !== null ) {
2572
- alternate . flags &= ~ PassiveUnmountPendingDev ;
2573
- }
2574
- }
2575
-
2576
- if ( typeof destroy === 'function' ) {
2577
- if ( __DEV__ ) {
2578
- setCurrentDebugFiberInDEV ( fiber ) ;
2579
- if (
2580
- enableProfilerTimer &&
2581
- enableProfilerCommitHooks &&
2582
- fiber . mode & ProfileMode
2583
- ) {
2584
- startPassiveEffectTimer ( ) ;
2585
- invokeGuardedCallback ( null , destroy , null ) ;
2586
- recordPassiveEffectDuration ( fiber ) ;
2587
- } else {
2588
- invokeGuardedCallback ( null , destroy , null ) ;
2589
- }
2590
- if ( hasCaughtError ( ) ) {
2591
- invariant ( fiber !== null , 'Should be working on an effect.' ) ;
2592
- const error = clearCaughtError ( ) ;
2593
- captureCommitPhaseError ( fiber , error ) ;
2594
- }
2595
- resetCurrentDebugFiberInDEV ( ) ;
2596
- } else {
2597
- try {
2598
- if (
2599
- enableProfilerTimer &&
2600
- enableProfilerCommitHooks &&
2601
- fiber . mode & ProfileMode
2602
- ) {
2603
- try {
2604
- startPassiveEffectTimer ( ) ;
2605
- destroy ( ) ;
2606
- } finally {
2607
- recordPassiveEffectDuration ( fiber ) ;
2608
- }
2609
- } else {
2610
- destroy ( ) ;
2611
- }
2612
- } catch ( error ) {
2613
- invariant ( fiber !== null , 'Should be working on an effect.' ) ;
2614
- captureCommitPhaseError ( fiber , error ) ;
2615
- }
2616
- }
2617
- }
2618
- }
2619
- // Second pass: Create new passive effects.
2547
+ commitPassiveUnmountEffects ( root . current ) ;
2620
2548
commitPassiveMountEffects ( root , root . current ) ;
2621
2549
2622
2550
// TODO: Move to commitPassiveMountEffects
@@ -3004,12 +2932,25 @@ function warnAboutUpdateOnUnmountedFiberInDEV(fiber) {
3004
2932
return ;
3005
2933
}
3006
2934
3007
- // If there are pending passive effects unmounts for this Fiber,
3008
- // we can assume that they would have prevented this update.
3009
- if ( ( fiber . flags & PassiveUnmountPendingDev ) !== NoFlags ) {
3010
- return ;
3011
- }
2935
+ if ( ( fiber . flags & PassiveStatic ) !== NoFlags ) {
2936
+ const updateQueue : FunctionComponentUpdateQueue | null = ( fiber . updateQueue : any ) ;
2937
+ if ( updateQueue !== null ) {
2938
+ const lastEffect = updateQueue . lastEffect ;
2939
+ if ( lastEffect !== null ) {
2940
+ const firstEffect = lastEffect . next ;
3012
2941
2942
+ let effect = firstEffect ;
2943
+ do {
2944
+ if ( effect . destroy !== undefined ) {
2945
+ if ( ( effect . tag & HookPassive ) !== NoHookEffect ) {
2946
+ return ;
2947
+ }
2948
+ }
2949
+ effect = effect . next ;
2950
+ } while ( effect !== firstEffect ) ;
2951
+ }
2952
+ }
2953
+ }
3013
2954
// We show the whole stack but dedupe on the top component's name because
3014
2955
// the problematic code almost always lies inside that component.
3015
2956
const componentName = getComponentName ( fiber . type ) || 'ReactComponent' ;
0 commit comments