@@ -30,6 +30,7 @@ import type {
3030import type { HookFlags } from './ReactHookEffectTags' ;
3131import type { Cache } from './ReactFiberCacheComponent.new' ;
3232import type { RootState } from './ReactFiberRoot.new' ;
33+ import { scheduleMicrotask } from './ReactFiberHostConfig' ;
3334import type {
3435 Transition ,
3536 TracingMarkerInstance ,
@@ -154,6 +155,7 @@ import {
154155 setIsRunningInsertionEffect ,
155156 getExecutionContext ,
156157 CommitContext ,
158+ RenderContext ,
157159 NoContext ,
158160} from './ReactFiberWorkLoop.new' ;
159161import {
@@ -182,6 +184,7 @@ import {releaseCache, retainCache} from './ReactFiberCacheComponent.new';
182184import { clearTransitionsForLanes } from './ReactFiberLane.new' ;
183185import {
184186 OffscreenVisible ,
187+ OffscreenDetached ,
185188 OffscreenPassiveEffectsConnected ,
186189} from './ReactFiberOffscreenComponent' ;
187190import {
@@ -1078,7 +1081,9 @@ function commitLayoutEffectOnFiber(
10781081 case OffscreenComponent : {
10791082 const isModernRoot = ( finishedWork . mode & ConcurrentMode ) !== NoMode ;
10801083 if ( isModernRoot ) {
1081- const isHidden = finishedWork . memoizedState !== null ;
1084+ const isHidden =
1085+ finishedWork . memoizedState !== null ||
1086+ finishedWork . stateNode . _visibility & OffscreenDetached ;
10821087 const newOffscreenSubtreeIsHidden =
10831088 isHidden || offscreenSubtreeIsHidden ;
10841089 if ( newOffscreenSubtreeIsHidden ) {
@@ -2255,6 +2260,23 @@ function getRetryCache(finishedWork) {
22552260 }
22562261}
22572262
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+
22582280function attachSuspenseRetryListeners (
22592281 finishedWork : Fiber ,
22602282 wakeables : Set < Wakeable > ,
@@ -2633,6 +2655,7 @@ function commitMutationEffectsOnFiber(
26332655 }
26342656
26352657 commitReconciliationEffects ( finishedWork ) ;
2658+ attachOffscreenActions ( finishedWork , root ) ;
26362659
26372660 if ( flags & Visibility ) {
26382661 const offscreenInstance : OffscreenInstance = finishedWork . stateNode ;
@@ -2659,7 +2682,10 @@ function commitMutationEffectsOnFiber(
26592682 }
26602683 }
26612684
2662- if ( supportsMutation ) {
2685+ if (
2686+ supportsMutation &&
2687+ ! ( offscreenInstance . _visibility & OffscreenDetached )
2688+ ) {
26632689 // TODO: This needs to run whenever there's an insertion or update
26642690 // inside a hidden Offscreen tree.
26652691 hideOrUnhideAllChildren ( offscreenBoundary , isHidden ) ;
0 commit comments