@@ -30,6 +30,7 @@ import type {
30
30
import type { HookFlags } from './ReactHookEffectTags' ;
31
31
import type { Cache } from './ReactFiberCacheComponent.new' ;
32
32
import type { RootState } from './ReactFiberRoot.new' ;
33
+ import { scheduleMicrotask } from './ReactFiberHostConfig' ;
33
34
import type {
34
35
Transition ,
35
36
TracingMarkerInstance ,
@@ -154,6 +155,7 @@ import {
154
155
setIsRunningInsertionEffect ,
155
156
getExecutionContext ,
156
157
CommitContext ,
158
+ RenderContext ,
157
159
NoContext ,
158
160
} from './ReactFiberWorkLoop.new' ;
159
161
import {
@@ -182,6 +184,7 @@ import {releaseCache, retainCache} from './ReactFiberCacheComponent.new';
182
184
import { clearTransitionsForLanes } from './ReactFiberLane.new' ;
183
185
import {
184
186
OffscreenVisible ,
187
+ OffscreenDetached ,
185
188
OffscreenPassiveEffectsConnected ,
186
189
} from './ReactFiberOffscreenComponent' ;
187
190
import {
@@ -1078,7 +1081,9 @@ function commitLayoutEffectOnFiber(
1078
1081
case OffscreenComponent : {
1079
1082
const isModernRoot = ( finishedWork . mode & ConcurrentMode ) !== NoMode ;
1080
1083
if ( isModernRoot ) {
1081
- const isHidden = finishedWork . memoizedState !== null ;
1084
+ const isHidden =
1085
+ finishedWork . memoizedState !== null ||
1086
+ finishedWork . stateNode . _visibility & OffscreenDetached ;
1082
1087
const newOffscreenSubtreeIsHidden =
1083
1088
isHidden || offscreenSubtreeIsHidden ;
1084
1089
if ( newOffscreenSubtreeIsHidden ) {
@@ -2255,6 +2260,23 @@ function getRetryCache(finishedWork) {
2255
2260
}
2256
2261
}
2257
2262
2263
+ function attachOffscreenActions ( offscreenFiber : Fiber , root : FiberRoot ) {
2264
+ offscreenFiber . stateNode . detach = ( ) => {
2265
+ const executionContext = getExecutionContext ( ) ;
2266
+ if ( ( executionContext & ( RenderContext | CommitContext ) ) !== NoContext ) {
2267
+ scheduleMicrotask ( ( ) => {
2268
+ offscreenFiber . stateNode . _visibility |= OffscreenDetached ;
2269
+ disappearLayoutEffects ( offscreenFiber ) ;
2270
+ disconnectPassiveEffect ( offscreenFiber ) ;
2271
+ } ) ;
2272
+ } else {
2273
+ offscreenFiber . stateNode . _visibility |= OffscreenDetached ;
2274
+ disappearLayoutEffects ( offscreenFiber ) ;
2275
+ disconnectPassiveEffect ( offscreenFiber ) ;
2276
+ }
2277
+ } ;
2278
+ }
2279
+
2258
2280
function attachSuspenseRetryListeners (
2259
2281
finishedWork : Fiber ,
2260
2282
wakeables : Set < Wakeable > ,
@@ -2633,6 +2655,7 @@ function commitMutationEffectsOnFiber(
2633
2655
}
2634
2656
2635
2657
commitReconciliationEffects ( finishedWork ) ;
2658
+ attachOffscreenActions ( finishedWork , root ) ;
2636
2659
2637
2660
if ( flags & Visibility ) {
2638
2661
const offscreenInstance : OffscreenInstance = finishedWork . stateNode ;
@@ -2659,7 +2682,10 @@ function commitMutationEffectsOnFiber(
2659
2682
}
2660
2683
}
2661
2684
2662
- if ( supportsMutation ) {
2685
+ if (
2686
+ supportsMutation &&
2687
+ ! ( offscreenInstance . _visibility & OffscreenDetached )
2688
+ ) {
2663
2689
// TODO: This needs to run whenever there's an insertion or update
2664
2690
// inside a hidden Offscreen tree.
2665
2691
hideOrUnhideAllChildren ( offscreenBoundary , isHidden ) ;
0 commit comments