@@ -26,6 +26,7 @@ import type {
2626 OffscreenState ,
2727 OffscreenInstance ,
2828 OffscreenQueue ,
29+ OffscreenProps ,
2930} from './ReactFiberOffscreenComponent' ;
3031import type { HookFlags } from './ReactHookEffectTags' ;
3132import type { Cache } from './ReactFiberCacheComponent.new' ;
@@ -1141,6 +1142,14 @@ function commitLayoutEffectOnFiber(
11411142 committedLanes ,
11421143 ) ;
11431144 }
1145+ if ( flags & Ref ) {
1146+ const props : OffscreenProps = finishedWork . memoizedProps ;
1147+ if ( props . mode === 'manual' ) {
1148+ safelyAttachRef ( finishedWork , finishedWork . return ) ;
1149+ } else {
1150+ safelyDetachRef ( finishedWork , finishedWork . return ) ;
1151+ }
1152+ }
11441153 break ;
11451154 }
11461155 default : {
@@ -1314,7 +1323,7 @@ function commitTransitionProgress(offscreenFiber: Fiber) {
13141323 const wasHidden = prevState !== null ;
13151324 const isHidden = nextState !== null ;
13161325
1317- const pendingMarkers = offscreenInstance . pendingMarkers ;
1326+ const pendingMarkers = offscreenInstance . _pendingMarkers ;
13181327 // If there is a name on the suspense boundary, store that in
13191328 // the pending boundaries.
13201329 let name = null ;
@@ -2144,6 +2153,7 @@ function commitDeletionEffectsOnFiber(
21442153 return ;
21452154 }
21462155 case OffscreenComponent : {
2156+ safelyDetachRef ( deletedFiber , nearestMountedAncestor ) ;
21472157 if ( deletedFiber . mode & ConcurrentMode ) {
21482158 // If this offscreen component is hidden, we already unmounted it. Before
21492159 // deleting the children, track that it's already unmounted so that we
@@ -2250,9 +2260,9 @@ function getRetryCache(finishedWork) {
22502260 }
22512261 case OffscreenComponent : {
22522262 const instance : OffscreenInstance = finishedWork . stateNode ;
2253- let retryCache = instance . retryCache ;
2263+ let retryCache = instance . _retryCache ;
22542264 if ( retryCache === null ) {
2255- retryCache = instance . retryCache = new PossiblyWeakSet ( ) ;
2265+ retryCache = instance . _retryCache = new PossiblyWeakSet ( ) ;
22562266 }
22572267 return retryCache ;
22582268 }
@@ -2623,6 +2633,12 @@ function commitMutationEffectsOnFiber(
26232633 return ;
26242634 }
26252635 case OffscreenComponent: {
2636+ if ( flags & Ref ) {
2637+ if ( current !== null ) {
2638+ safelyDetachRef ( current , current . return ) ;
2639+ }
2640+ }
2641+
26262642 const newState : OffscreenState | null = finishedWork . memoizedState ;
26272643 const isHidden = newState !== null ;
26282644 const wasHidden = current !== null && current . memoizedState !== null ;
@@ -2651,9 +2667,9 @@ function commitMutationEffectsOnFiber(
26512667 // Track the current state on the Offscreen instance so we can
26522668 // read it during an event
26532669 if ( isHidden ) {
2654- offscreenInstance . visibility &= ~ OffscreenVisible ;
2670+ offscreenInstance . _visibility &= ~ OffscreenVisible ;
26552671 } else {
2656- offscreenInstance . visibility |= OffscreenVisible ;
2672+ offscreenInstance . _visibility |= OffscreenVisible ;
26572673 }
26582674
26592675 if ( isHidden ) {
@@ -2838,6 +2854,9 @@ export function disappearLayoutEffects(finishedWork: Fiber) {
28382854 break ;
28392855 }
28402856 case OffscreenComponent : {
2857+ // TODO (Offscreen) Check: flags & RefStatic
2858+ safelyDetachRef ( finishedWork , finishedWork . return ) ;
2859+
28412860 const isHidden = finishedWork . memoizedState !== null ;
28422861 if ( isHidden ) {
28432862 // Nested Offscreen tree is already hidden. Don't disappear
@@ -2985,6 +3004,8 @@ export function reappearLayoutEffects(
29853004 includeWorkInProgressEffects ,
29863005 ) ;
29873006 }
3007+ // TODO: Check flags & Ref
3008+ safelyAttachRef ( finishedWork , finishedWork . return ) ;
29883009 break ;
29893010 }
29903011 default : {
@@ -3098,10 +3119,10 @@ function commitOffscreenPassiveMountEffects(
30983119 // Add all the transitions saved in the update queue during
30993120 // the render phase (ie the transitions associated with this boundary)
31003121 // into the transitions set.
3101- if ( instance . transitions === null ) {
3102- instance . transitions = new Set ( ) ;
3122+ if ( instance . _transitions === null ) {
3123+ instance . _transitions = new Set ( ) ;
31033124 }
3104- instance . transitions . add ( transition ) ;
3125+ instance . _transitions . add ( transition ) ;
31053126 } ) ;
31063127 }
31073128
@@ -3114,17 +3135,17 @@ function commitOffscreenPassiveMountEffects(
31143135 // caused them
31153136 if ( markerTransitions !== null ) {
31163137 markerTransitions . forEach ( transition => {
3117- if ( instance . transitions === null ) {
3118- instance . transitions = new Set ( ) ;
3119- } else if ( instance . transitions . has ( transition ) ) {
3138+ if ( instance . _transitions === null ) {
3139+ instance . _transitions = new Set ( ) ;
3140+ } else if ( instance . _transitions . has ( transition ) ) {
31203141 if ( markerInstance . pendingBoundaries === null ) {
31213142 markerInstance . pendingBoundaries = new Map ( ) ;
31223143 }
3123- if ( instance . pendingMarkers === null ) {
3124- instance . pendingMarkers = new Set ( ) ;
3144+ if ( instance . _pendingMarkers === null ) {
3145+ instance . _pendingMarkers = new Set ( ) ;
31253146 }
31263147
3127- instance . pendingMarkers . add ( markerInstance ) ;
3148+ instance . _pendingMarkers . add ( markerInstance ) ;
31283149 }
31293150 } ) ;
31303151 }
@@ -3139,8 +3160,8 @@ function commitOffscreenPassiveMountEffects(
31393160
31403161 // TODO: Refactor this into an if/else branch
31413162 if ( ! isHidden ) {
3142- instance . transitions = null ;
3143- instance . pendingMarkers = null ;
3163+ instance . _transitions = null ;
3164+ instance . _pendingMarkers = null ;
31443165 }
31453166 }
31463167}
@@ -3320,7 +3341,7 @@ function commitPassiveMountOnFiber(
33203341 const isHidden = nextState !== null ;
33213342
33223343 if ( isHidden ) {
3323- if ( instance . visibility & OffscreenPassiveEffectsConnected ) {
3344+ if ( instance . _visibility & OffscreenPassiveEffectsConnected ) {
33243345 // The effects are currently connected. Update them.
33253346 recursivelyTraversePassiveMountEffects (
33263347 finishedRoot ,
@@ -3345,7 +3366,7 @@ function commitPassiveMountOnFiber(
33453366 }
33463367 } else {
33473368 // Legacy Mode: Fire the effects even if the tree is hidden.
3348- instance . visibility |= OffscreenPassiveEffectsConnected ;
3369+ instance . _visibility |= OffscreenPassiveEffectsConnected ;
33493370 recursivelyTraversePassiveMountEffects (
33503371 finishedRoot ,
33513372 finishedWork ,
@@ -3356,7 +3377,7 @@ function commitPassiveMountOnFiber(
33563377 }
33573378 } else {
33583379 // Tree is visible
3359- if ( instance . visibility & OffscreenPassiveEffectsConnected ) {
3380+ if ( instance . _visibility & OffscreenPassiveEffectsConnected ) {
33603381 // The effects are currently connected. Update them.
33613382 recursivelyTraversePassiveMountEffects (
33623383 finishedRoot ,
@@ -3368,7 +3389,7 @@ function commitPassiveMountOnFiber(
33683389 // The effects are currently disconnected. Reconnect them, while also
33693390 // firing effects inside newly mounted trees. This also applies to
33703391 // the initial render.
3371- instance . visibility |= OffscreenPassiveEffectsConnected ;
3392+ instance . _visibility |= OffscreenPassiveEffectsConnected ;
33723393
33733394 const includeWorkInProgressEffects =
33743395 ( finishedWork . subtreeFlags & PassiveMask ) !== NoFlags ;
@@ -3500,7 +3521,7 @@ export function reconnectPassiveEffects(
35003521 const isHidden = nextState !== null ;
35013522
35023523 if ( isHidden ) {
3503- if ( instance . visibility & OffscreenPassiveEffectsConnected ) {
3524+ if ( instance . _visibility & OffscreenPassiveEffectsConnected ) {
35043525 // The effects are currently connected. Update them.
35053526 recursivelyTraverseReconnectPassiveEffects (
35063527 finishedRoot ,
@@ -3526,7 +3547,7 @@ export function reconnectPassiveEffects(
35263547 }
35273548 } else {
35283549 // Legacy Mode: Fire the effects even if the tree is hidden.
3529- instance . visibility |= OffscreenPassiveEffectsConnected ;
3550+ instance . _visibility |= OffscreenPassiveEffectsConnected ;
35303551 recursivelyTraverseReconnectPassiveEffects (
35313552 finishedRoot ,
35323553 finishedWork ,
@@ -3544,7 +3565,7 @@ export function reconnectPassiveEffects(
35443565 // continue traversing the tree and firing all the effects.
35453566 //
35463567 // We do need to set the "connected" flag on the instance, though.
3547- instance . visibility |= OffscreenPassiveEffectsConnected ;
3568+ instance . _visibility |= OffscreenPassiveEffectsConnected ;
35483569
35493570 recursivelyTraverseReconnectPassiveEffects (
35503571 finishedRoot ,
@@ -3799,7 +3820,7 @@ function commitPassiveUnmountOnFiber(finishedWork: Fiber): void {
37993820
38003821 if (
38013822 isHidden &&
3802- instance . visibility & OffscreenPassiveEffectsConnected &&
3823+ instance . _visibility & OffscreenPassiveEffectsConnected &&
38033824 // For backwards compatibility, don't unmount when a tree suspends. In
38043825 // the future we may change this to unmount after a delay.
38053826 ( finishedWork . return === null ||
@@ -3809,7 +3830,7 @@ function commitPassiveUnmountOnFiber(finishedWork: Fiber): void {
38093830 // TODO: Add option or heuristic to delay before disconnecting the
38103831 // effects. Then if the tree reappears before the delay has elapsed, we
38113832 // can skip toggling the effects entirely.
3812- instance . visibility &= ~ OffscreenPassiveEffectsConnected ;
3833+ instance . _visibility &= ~ OffscreenPassiveEffectsConnected ;
38133834 recursivelyTraverseDisconnectPassiveEffects ( finishedWork ) ;
38143835 } else {
38153836 recursivelyTraversePassiveUnmountEffects ( finishedWork ) ;
@@ -3873,8 +3894,8 @@ export function disconnectPassiveEffect(finishedWork: Fiber): void {
38733894 }
38743895 case OffscreenComponent: {
38753896 const instance : OffscreenInstance = finishedWork . stateNode ;
3876- if ( instance . visibility & OffscreenPassiveEffectsConnected ) {
3877- instance . visibility &= ~ OffscreenPassiveEffectsConnected ;
3897+ if ( instance . _visibility & OffscreenPassiveEffectsConnected ) {
3898+ instance . _visibility &= ~ OffscreenPassiveEffectsConnected ;
38783899 recursivelyTraverseDisconnectPassiveEffects ( finishedWork ) ;
38793900 } else {
38803901 // The effects are already disconnected.
@@ -4002,7 +4023,7 @@ function commitPassiveUnmountInsideDeletedTreeOnFiber(
40024023 // We need to mark this fiber's parents as deleted
40034024 const offscreenFiber : Fiber = ( current . child : any ) ;
40044025 const instance : OffscreenInstance = offscreenFiber . stateNode ;
4005- const transitions = instance . transitions ;
4026+ const transitions = instance . _transitions ;
40064027 if ( transitions !== null ) {
40074028 const abortReason = {
40084029 reason : 'suspense' ,
0 commit comments