@@ -114,14 +114,9 @@ import {
114114} from './ReactFiberWorkLoop' ;
115115import {
116116 NoEffect as NoHookEffect ,
117- NoEffectPassiveUnmountFiber ,
118- UnmountSnapshot ,
119- UnmountMutation ,
120- MountMutation ,
121- UnmountLayout ,
122- MountLayout ,
123- UnmountPassive ,
124- MountPassive ,
117+ HasEffect as HookHasEffect ,
118+ Layout as HookLayout ,
119+ Passive as HookPassive ,
125120} from './ReactHookEffectTags' ;
126121import { didWarnAboutReassigningProps } from './ReactFiberBeginWork' ;
127122import { runWithPriority , NormalPriority } from './SchedulerWithReactIntegration' ;
@@ -253,7 +248,6 @@ function commitBeforeMutationLifeCycles(
253248 case ForwardRef :
254249 case SimpleMemoComponent :
255250 case Chunk : {
256- commitHookEffectList ( UnmountSnapshot , NoHookEffect , finishedWork ) ;
257251 return ;
258252 }
259253 case ClassComponent : {
@@ -342,15 +336,21 @@ function commitHookEffectList(
342336 const firstEffect = lastEffect . next ;
343337 let effect = firstEffect ;
344338 do {
345- if ( ( effect . tag & unmountTag ) !== NoHookEffect ) {
339+ if (
340+ ( effect . tag & HookHasEffect ) !== NoHookEffect &&
341+ ( effect . tag & unmountTag ) !== NoHookEffect
342+ ) {
346343 // Unmount
347344 const destroy = effect . destroy ;
348345 effect . destroy = undefined ;
349346 if ( destroy !== undefined ) {
350347 destroy ( ) ;
351348 }
352349 }
353- if ( ( effect . tag & mountTag ) !== NoHookEffect ) {
350+ if (
351+ ( effect . tag & HookHasEffect ) !== NoHookEffect &&
352+ ( effect . tag & mountTag ) !== NoHookEffect
353+ ) {
354354 // Mount
355355 const create = effect . create ;
356356 effect . destroy = create ( ) ;
@@ -401,8 +401,11 @@ export function commitPassiveHookEffects(finishedWork: Fiber): void {
401401 case ForwardRef :
402402 case SimpleMemoComponent :
403403 case Chunk : {
404- commitHookEffectList ( UnmountPassive , NoHookEffect , finishedWork ) ;
405- commitHookEffectList ( NoHookEffect , MountPassive , finishedWork ) ;
404+ // TODO (#17945) We should call all passive destroy functions (for all fibers)
405+ // before calling any create functions. The current approach only serializes
406+ // these for a single fiber.
407+ commitHookEffectList ( HookPassive , NoHookEffect , finishedWork ) ;
408+ commitHookEffectList ( NoHookEffect , HookPassive , finishedWork ) ;
406409 break ;
407410 }
408411 default :
@@ -422,7 +425,11 @@ function commitLifeCycles(
422425 case ForwardRef :
423426 case SimpleMemoComponent :
424427 case Chunk : {
425- commitHookEffectList ( UnmountLayout , MountLayout , finishedWork ) ;
428+ // At this point layout effects have already been destroyed (during mutation phase).
429+ // This is done to prevent sibling component effects from interfering with each other,
430+ // e.g. a destroy function in one component should never override a ref set
431+ // by a create function in another component during the same commit.
432+ commitHookEffectList ( NoHookEffect , HookLayout , finishedWork ) ;
426433 return ;
427434 }
428435 case ClassComponent : {
@@ -764,10 +771,7 @@ function commitUnmount(
764771 do {
765772 const { destroy, tag} = effect ;
766773 if ( destroy !== undefined ) {
767- if (
768- ( tag & UnmountPassive ) !== NoHookEffect ||
769- ( tag & NoEffectPassiveUnmountFiber ) !== NoHookEffect
770- ) {
774+ if ( ( tag & HookPassive ) !== NoHookEffect ) {
771775 enqueuePendingPassiveEffectDestroyFn ( destroy ) ;
772776 } else {
773777 safelyCallDestroy ( current , destroy ) ;
@@ -1306,11 +1310,12 @@ function commitWork(current: Fiber | null, finishedWork: Fiber): void {
13061310 case MemoComponent :
13071311 case SimpleMemoComponent :
13081312 case Chunk : {
1309- // Note: We currently never use MountMutation, but useLayoutEffect uses UnmountMutation.
1310- // This is to ensure ALL destroy fns are run before create fns,
1311- // without requiring us to traverse the effects list an extra time during commit.
1312- // This sequence prevents sibling destroy and create fns from interfering with each other.
1313- commitHookEffectList ( UnmountMutation , MountMutation , finishedWork ) ;
1313+ // Layout effects are destroyed during the mutation phase so that all
1314+ // destroy functions for all fibers are called before any create functions.
1315+ // This prevents sibling component effects from interfering with each other,
1316+ // e.g. a destroy function in one component should never override a ref set
1317+ // by a create function in another component during the same commit.
1318+ commitHookEffectList ( HookLayout , NoHookEffect , finishedWork ) ;
13141319 return ;
13151320 }
13161321 case Profiler : {
@@ -1348,11 +1353,12 @@ function commitWork(current: Fiber | null, finishedWork: Fiber): void {
13481353 case MemoComponent :
13491354 case SimpleMemoComponent :
13501355 case Chunk : {
1351- // Note: We currently never use MountMutation, but useLayoutEffect uses UnmountMutation.
1352- // This is to ensure ALL destroy fns are run before create fns,
1353- // without requiring us to traverse the effects list an extra time during commit.
1354- // This sequence prevents sibling destroy and create fns from interfering with each other.
1355- commitHookEffectList ( UnmountMutation , MountMutation , finishedWork ) ;
1356+ // Layout effects are destroyed during the mutation phase so that all
1357+ // destroy functions for all fibers are called before any create functions.
1358+ // This prevents sibling component effects from interfering with each other,
1359+ // e.g. a destroy function in one component should never override a ref set
1360+ // by a create function in another component during the same commit.
1361+ commitHookEffectList ( HookLayout , NoHookEffect , finishedWork ) ;
13561362 return ;
13571363 }
13581364 case ClassComponent : {
0 commit comments