@@ -132,6 +132,8 @@ import {
132
132
commitBeforeMutationLifeCycles as commitBeforeMutationEffectOnFiber ,
133
133
commitLifeCycles as commitLayoutEffectOnFiber ,
134
134
commitPassiveHookEffects ,
135
+ commitPassiveHookUnmountEffects ,
136
+ commitPassiveHookMountEffects ,
135
137
commitPlacement ,
136
138
commitWork ,
137
139
commitDeletion ,
@@ -2212,34 +2214,108 @@ function flushPassiveEffectsImpl() {
2212
2214
invokeGuardedCallback ( null , destroy , null ) ;
2213
2215
}
2214
2216
pendingUnmountedPassiveEffectDestroyFunctions . length = 0 ;
2215
- }
2216
2217
2217
- // Note: This currently assumes there are no passive effects on the root
2218
- // fiber, because the root is not part of its own effect list. This could
2219
- // change in the future.
2220
- let effect = root . current . firstEffect ;
2221
- while ( effect !== null ) {
2222
- if ( __DEV__ ) {
2223
- setCurrentDebugFiberInDEV ( effect ) ;
2224
- invokeGuardedCallback ( null , commitPassiveHookEffects , null , effect ) ;
2225
- if ( hasCaughtError ( ) ) {
2226
- invariant ( effect !== null , 'Should be working on an effect.' ) ;
2227
- const error = clearCaughtError ( ) ;
2228
- captureCommitPhaseError ( effect , error ) ;
2218
+ // It's important that ALL pending passive effect destroy functions are called
2219
+ // before ANY passive effect create functions are called.
2220
+ // Otherwise effects in sibling components might interfere with each other.
2221
+ // e.g. a destroy function in one component may unintentionally override a ref
2222
+ // value set by a create function in another component.
2223
+ // Layout effects have the same constraint.
2224
+
2225
+ // First pass: Destroy stale passive effects.
2226
+ //
2227
+ // Note: This currently assumes there are no passive effects on the root fiber
2228
+ // because the root is not part of its own effect list.
2229
+ // This could change in the future.
2230
+ let effect = root . current . firstEffect ;
2231
+ while ( effect !== null ) {
2232
+ if ( __DEV__ ) {
2233
+ setCurrentDebugFiberInDEV ( effect ) ;
2234
+ invokeGuardedCallback (
2235
+ null ,
2236
+ commitPassiveHookUnmountEffects ,
2237
+ null ,
2238
+ effect ,
2239
+ ) ;
2240
+ if ( hasCaughtError ( ) ) {
2241
+ invariant ( effect !== null , 'Should be working on an effect.' ) ;
2242
+ const error = clearCaughtError ( ) ;
2243
+ captureCommitPhaseError ( effect , error ) ;
2244
+ }
2245
+ resetCurrentDebugFiberInDEV ( ) ;
2246
+ } else {
2247
+ try {
2248
+ commitPassiveHookUnmountEffects ( effect ) ;
2249
+ } catch ( error ) {
2250
+ invariant ( effect !== null , 'Should be working on an effect.' ) ;
2251
+ captureCommitPhaseError ( effect , error ) ;
2252
+ }
2229
2253
}
2230
- resetCurrentDebugFiberInDEV ( ) ;
2231
- } else {
2232
- try {
2233
- commitPassiveHookEffects ( effect ) ;
2234
- } catch ( error ) {
2235
- invariant ( effect !== null , 'Should be working on an effect.' ) ;
2236
- captureCommitPhaseError ( effect , error ) ;
2254
+ effect = effect . nextEffect ;
2255
+ }
2256
+
2257
+ // Second pass: Create new passive effects.
2258
+ //
2259
+ // Note: This currently assumes there are no passive effects on the root fiber
2260
+ // because the root is not part of its own effect list.
2261
+ // This could change in the future.
2262
+ effect = root . current . firstEffect ;
2263
+ while ( effect !== null ) {
2264
+ if ( __DEV__ ) {
2265
+ setCurrentDebugFiberInDEV ( effect ) ;
2266
+ invokeGuardedCallback (
2267
+ null ,
2268
+ commitPassiveHookMountEffects ,
2269
+ null ,
2270
+ effect ,
2271
+ ) ;
2272
+ if ( hasCaughtError ( ) ) {
2273
+ invariant ( effect !== null , 'Should be working on an effect.' ) ;
2274
+ const error = clearCaughtError ( ) ;
2275
+ captureCommitPhaseError ( effect , error ) ;
2276
+ }
2277
+ resetCurrentDebugFiberInDEV ( ) ;
2278
+ } else {
2279
+ try {
2280
+ commitPassiveHookMountEffects ( effect ) ;
2281
+ } catch ( error ) {
2282
+ invariant ( effect !== null , 'Should be working on an effect.' ) ;
2283
+ captureCommitPhaseError ( effect , error ) ;
2284
+ }
2285
+ }
2286
+ const nextNextEffect = effect . nextEffect ;
2287
+ // Remove nextEffect pointer to assist GC
2288
+ effect . nextEffect = null ;
2289
+ effect = nextNextEffect ;
2290
+ }
2291
+ } else {
2292
+ // Note: This currently assumes there are no passive effects on the root fiber
2293
+ // because the root is not part of its own effect list.
2294
+ // This could change in the future.
2295
+ let effect = root . current . firstEffect ;
2296
+ while ( effect !== null ) {
2297
+ if ( __DEV__ ) {
2298
+ setCurrentDebugFiberInDEV ( effect ) ;
2299
+ invokeGuardedCallback ( null , commitPassiveHookEffects , null , effect ) ;
2300
+ if ( hasCaughtError ( ) ) {
2301
+ invariant ( effect !== null , 'Should be working on an effect.' ) ;
2302
+ const error = clearCaughtError ( ) ;
2303
+ captureCommitPhaseError ( effect , error ) ;
2304
+ }
2305
+ resetCurrentDebugFiberInDEV ( ) ;
2306
+ } else {
2307
+ try {
2308
+ commitPassiveHookEffects ( effect ) ;
2309
+ } catch ( error ) {
2310
+ invariant ( effect !== null , 'Should be working on an effect.' ) ;
2311
+ captureCommitPhaseError ( effect , error ) ;
2312
+ }
2237
2313
}
2314
+ const nextNextEffect = effect . nextEffect ;
2315
+ // Remove nextEffect pointer to assist GC
2316
+ effect . nextEffect = null ;
2317
+ effect = nextNextEffect ;
2238
2318
}
2239
- const nextNextEffect = effect . nextEffect ;
2240
- // Remove nextEffect pointer to assist GC
2241
- effect . nextEffect = null ;
2242
- effect = nextNextEffect ;
2243
2319
}
2244
2320
2245
2321
if ( enableSchedulerTracing ) {
0 commit comments