@@ -15,6 +15,7 @@ import type {Interaction} from 'scheduler/src/Tracing';
1515import type { SuspenseState } from './ReactFiberSuspenseComponent.new' ;
1616import type { Effect as HookEffect } from './ReactFiberHooks.new' ;
1717import type { StackCursor } from './ReactFiberStack.new' ;
18+ import type { FunctionComponentUpdateQueue } from './ReactFiberHooks.new' ;
1819
1920import {
2021 warnAboutDeprecatedLifecycles ,
@@ -50,6 +51,10 @@ import {
5051 flushSyncCallbackQueue ,
5152 scheduleSyncCallback ,
5253} from './SchedulerWithReactIntegration.new' ;
54+ import {
55+ NoFlags as NoHookEffect ,
56+ Passive as HookPassive ,
57+ } from './ReactHookEffectTags' ;
5358import {
5459 logCommitStarted ,
5560 logCommitStopped ,
@@ -127,7 +132,7 @@ import {
127132 Snapshot ,
128133 Callback ,
129134 Passive ,
130- PassiveUnmountPendingDev ,
135+ PassiveStatic ,
131136 Incomplete ,
132137 HostEffectMask ,
133138 Hydrating ,
@@ -194,6 +199,7 @@ import {
194199 commitResetTextContent ,
195200 isSuspenseBoundaryBeingHidden ,
196201 commitPassiveMountEffects ,
202+ commitPassiveUnmountEffects ,
197203 detachFiberAfterEffects ,
198204} from './ReactFiberCommitWork.new' ;
199205import { enqueueUpdate } from './ReactUpdateQueue.new' ;
@@ -213,9 +219,7 @@ import {
213219import {
214220 markNestedUpdateScheduled ,
215221 recordCommitTime ,
216- recordPassiveEffectDuration ,
217222 resetNestedUpdateFlag ,
218- startPassiveEffectTimer ,
219223 startProfilerTimer ,
220224 stopProfilerTimerIfRunningAndRecordDelta ,
221225 syncNestedUpdateFlag ,
@@ -341,7 +345,6 @@ let rootDoesHavePassiveEffects: boolean = false;
341345let rootWithPendingPassiveEffects: FiberRoot | null = null;
342346let pendingPassiveEffectsRenderPriority: ReactPriorityLevel = NoSchedulerPriority;
343347let pendingPassiveEffectsLanes: Lanes = NoLanes;
344- let pendingPassiveHookEffectsUnmount: Array< HookEffect | Fiber > = [];
345348let pendingPassiveProfilerEffects: Array< Fiber > = [];
346349
347350let rootsWithPendingDiscreteUpdates: Set< FiberRoot > | null = null;
@@ -2499,14 +2502,6 @@ export function enqueuePendingPassiveHookEffectUnmount(
24992502 fiber : Fiber ,
25002503 effect : HookEffect ,
25012504) : 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- }
25102505 if ( ! rootDoesHavePassiveEffects ) {
25112506 rootDoesHavePassiveEffects = true ;
25122507 scheduleCallback ( NormalSchedulerPriority , ( ) => {
@@ -2549,74 +2544,7 @@ function flushPassiveEffectsImpl() {
25492544 executionContext |= CommitContext ;
25502545 const prevInteractions = pushInteractions ( root ) ;
25512546
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 ) ;
26202548 commitPassiveMountEffects ( root , root . current ) ;
26212549
26222550 // TODO: Move to commitPassiveMountEffects
@@ -3004,12 +2932,25 @@ function warnAboutUpdateOnUnmountedFiberInDEV(fiber) {
30042932 return ;
30052933 }
30062934
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 ;
30122941
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+ }
30132954 // We show the whole stack but dedupe on the top component's name because
30142955 // the problematic code almost always lies inside that component.
30152956 const componentName = getComponentName ( fiber . type ) || 'ReactComponent' ;
0 commit comments