@@ -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,26 @@ function getRetryCache(finishedWork) {
2255
2260
}
2256
2261
}
2257
2262
2263
+ export function detachOffscreenInstance ( instance : OffscreenInstance ) : void {
2264
+ const currentOffscreenFiber = instance . _current ;
2265
+ if ( currentOffscreenFiber === null ) {
2266
+ throw new Error ( 'TODO: error message' ) ;
2267
+ }
2268
+
2269
+ const executionContext = getExecutionContext ( ) ;
2270
+ if ( ( executionContext & ( RenderContext | CommitContext ) ) !== NoContext ) {
2271
+ scheduleMicrotask ( ( ) => {
2272
+ instance . _visibility |= OffscreenDetached ;
2273
+ disappearLayoutEffects ( currentOffscreenFiber ) ;
2274
+ disconnectPassiveEffect ( currentOffscreenFiber ) ;
2275
+ } ) ;
2276
+ } else {
2277
+ instance . _visibility |= OffscreenDetached ;
2278
+ disappearLayoutEffects ( currentOffscreenFiber ) ;
2279
+ disconnectPassiveEffect ( currentOffscreenFiber ) ;
2280
+ }
2281
+ }
2282
+
2258
2283
function attachSuspenseRetryListeners (
2259
2284
finishedWork : Fiber ,
2260
2285
wakeables : Set < Wakeable > ,
@@ -2639,6 +2664,7 @@ function commitMutationEffectsOnFiber(
2639
2664
}
2640
2665
2641
2666
commitReconciliationEffects ( finishedWork ) ;
2667
+ finishedWork . stateNode . _current = finishedWork ;
2642
2668
2643
2669
if ( flags & Visibility ) {
2644
2670
const offscreenInstance : OffscreenInstance = finishedWork . stateNode ;
@@ -2665,7 +2691,10 @@ function commitMutationEffectsOnFiber(
2665
2691
}
2666
2692
}
2667
2693
2668
- if ( supportsMutation ) {
2694
+ if (
2695
+ supportsMutation &&
2696
+ ! ( offscreenInstance . _visibility & OffscreenDetached )
2697
+ ) {
2669
2698
// TODO: This needs to run whenever there's an insertion or update
2670
2699
// inside a hidden Offscreen tree.
2671
2700
hideOrUnhideAllChildren ( offscreenBoundary , isHidden ) ;
0 commit comments