@@ -27,7 +27,6 @@ import type {
2727 SuspenseState ,
2828 SuspenseListRenderState ,
2929} from './ReactFiberSuspenseComponent.old' ;
30- import type { SuspenseContext } from './ReactFiberSuspenseContext.old' ;
3130import type { OffscreenState } from './ReactFiberOffscreenComponent' ;
3231import type { TracingMarkerInstance } from './ReactFiberTracingMarkerComponent.old' ;
3332import type { Cache } from './ReactFiberCacheComponent.old' ;
@@ -110,14 +109,17 @@ import {
110109} from './ReactFiberHostContext.old' ;
111110import {
112111 suspenseStackCursor ,
113- InvisibleParentSuspenseContext ,
114- hasSuspenseContext ,
115- popSuspenseContext ,
116- pushSuspenseContext ,
117- setShallowSuspenseContext ,
112+ popSuspenseListContext ,
113+ popSuspenseHandler ,
114+ pushSuspenseListContext ,
115+ setShallowSuspenseListContext ,
118116 ForceSuspenseFallback ,
119- setDefaultShallowSuspenseContext ,
117+ setDefaultShallowSuspenseListContext ,
120118} from './ReactFiberSuspenseContext.old' ;
119+ import {
120+ popHiddenContext ,
121+ isCurrentTreeHidden ,
122+ } from './ReactFiberHiddenContext.old' ;
121123import { findFirstSuspended } from './ReactFiberSuspenseComponent.old' ;
122124import {
123125 isContextProvider as isLegacyContextProvider ,
@@ -147,9 +149,7 @@ import {
147149 renderDidSuspend ,
148150 renderDidSuspendDelayIfPossible ,
149151 renderHasNotSuspendedYet ,
150- popRenderLanes ,
151152 getRenderTargetTime ,
152- subtreeRenderLanes ,
153153 getWorkInProgressTransitions ,
154154} from './ReactFiberWorkLoop.old' ;
155155import {
@@ -1086,7 +1086,7 @@ function completeWork(
10861086 return null ;
10871087 }
10881088 case SuspenseComponent : {
1089- popSuspenseContext ( workInProgress ) ;
1089+ popSuspenseHandler ( workInProgress ) ;
10901090 const nextState : null | SuspenseState = workInProgress . memoizedState ;
10911091
10921092 // Special path for dehydrated boundaries. We may eventually move this
@@ -1195,25 +1195,23 @@ function completeWork(
11951195 // If this render already had a ping or lower pri updates,
11961196 // and this is the first time we know we're going to suspend we
11971197 // should be able to immediately restart from within throwException.
1198- const hasInvisibleChildContext =
1199- current === null &&
1200- ( workInProgress . memoizedProps . unstable_avoidThisFallback !==
1201- true ||
1202- ! enableSuspenseAvoidThisFallback ) ;
1203- if (
1204- hasInvisibleChildContext ||
1205- hasSuspenseContext (
1206- suspenseStackCursor . current ,
1207- ( InvisibleParentSuspenseContext : SuspenseContext ) ,
1208- )
1209- ) {
1210- // If this was in an invisible tree or a new render, then showing
1211- // this boundary is ok.
1212- renderDidSuspend ( ) ;
1213- } else {
1214- // Otherwise, we're going to have to hide content so we should
1215- // suspend for longer if possible.
1198+
1199+ // Check if this is a "bad" fallback state or a good one. A bad
1200+ // fallback state is one that we only show as a last resort; if this
1201+ // is a transition, we'll block it from displaying, and wait for
1202+ // more data to arrive.
1203+ const isBadFallback =
1204+ // It's bad to switch to a fallback if content is already visible
1205+ ( current !== null && ! prevDidTimeout && ! isCurrentTreeHidden ( ) ) ||
1206+ // Experimental: Some fallbacks are always bad
1207+ ( enableSuspenseAvoidThisFallback &&
1208+ workInProgress . memoizedProps . unstable_avoidThisFallback ===
1209+ true ) ;
1210+
1211+ if ( isBadFallback ) {
12161212 renderDidSuspendDelayIfPossible ( ) ;
1213+ } else {
1214+ renderDidSuspend ( ) ;
12171215 }
12181216 }
12191217 }
@@ -1275,7 +1273,7 @@ function completeWork(
12751273 return null ;
12761274 }
12771275 case SuspenseListComponent: {
1278- popSuspenseContext ( workInProgress ) ;
1276+ popSuspenseListContext ( workInProgress ) ;
12791277
12801278 const renderState : null | SuspenseListRenderState =
12811279 workInProgress . memoizedState ;
@@ -1341,11 +1339,11 @@ function completeWork(
13411339 workInProgress . subtreeFlags = NoFlags ;
13421340 resetChildFibers ( workInProgress , renderLanes ) ;
13431341
1344- // Set up the Suspense Context to force suspense and immediately
1345- // rerender the children.
1346- pushSuspenseContext (
1342+ // Set up the Suspense List Context to force suspense and
1343+ // immediately rerender the children.
1344+ pushSuspenseListContext (
13471345 workInProgress ,
1348- setShallowSuspenseContext (
1346+ setShallowSuspenseListContext (
13491347 suspenseStackCursor . current ,
13501348 ForceSuspenseFallback ,
13511349 ) ,
@@ -1468,14 +1466,16 @@ function completeWork(
14681466 // setting it the first time we go from not suspended to suspended.
14691467 let suspenseContext = suspenseStackCursor . current ;
14701468 if ( didSuspendAlready ) {
1471- suspenseContext = setShallowSuspenseContext (
1469+ suspenseContext = setShallowSuspenseListContext (
14721470 suspenseContext ,
14731471 ForceSuspenseFallback ,
14741472 ) ;
14751473 } else {
1476- suspenseContext = setDefaultShallowSuspenseContext ( suspenseContext ) ;
1474+ suspenseContext = setDefaultShallowSuspenseListContext (
1475+ suspenseContext ,
1476+ ) ;
14771477 }
1478- pushSuspenseContext ( workInProgress , suspenseContext ) ;
1478+ pushSuspenseListContext ( workInProgress , suspenseContext ) ;
14791479 // Do a pass over the next row.
14801480 // Don't bubble properties in this case.
14811481 return next ;
@@ -1508,7 +1508,8 @@ function completeWork(
15081508 }
15091509 case OffscreenComponent:
15101510 case LegacyHiddenComponent: {
1511- popRenderLanes ( workInProgress ) ;
1511+ popSuspenseHandler ( workInProgress ) ;
1512+ popHiddenContext ( workInProgress ) ;
15121513 const nextState : OffscreenState | null = workInProgress . memoizedState ;
15131514 const nextIsHidden = nextState !== null ;
15141515
@@ -1529,7 +1530,11 @@ function completeWork(
15291530 } else {
15301531 // Don't bubble properties for hidden children unless we're rendering
15311532 // at offscreen priority.
1532- if ( includesSomeLane ( subtreeRenderLanes , ( OffscreenLane : Lane ) ) ) {
1533+ if (
1534+ includesSomeLane ( renderLanes , ( OffscreenLane : Lane ) ) &&
1535+ // Also don't bubble if the tree suspended
1536+ ( workInProgress . flags & DidCapture ) === NoLanes
1537+ ) {
15331538 bubbleProperties ( workInProgress ) ;
15341539 // Check if there was an insertion or update in the hidden subtree.
15351540 // If so, we need to hide those nodes in the commit phase, so
@@ -1544,6 +1549,12 @@ function completeWork(
15441549 }
15451550 }
15461551
1552+ if ( workInProgress . updateQueue !== null ) {
1553+ // Schedule an effect to attach Suspense retry listeners
1554+ // TODO: Move to passive phase
1555+ workInProgress . flags |= Update ;
1556+ }
1557+
15471558 if ( enableCache ) {
15481559 let previousCache : Cache | null = null ;
15491560 if (
0 commit comments