@@ -128,6 +128,7 @@ import {
128
128
setShallowSuspenseListContext ,
129
129
ForceSuspenseFallback ,
130
130
setDefaultShallowSuspenseListContext ,
131
+ getSuspenseHandler ,
131
132
} from './ReactFiberSuspenseContext' ;
132
133
import { popHiddenContext } from './ReactFiberHiddenContext' ;
133
134
import { findFirstSuspended } from './ReactFiberSuspenseComponent' ;
@@ -534,33 +535,31 @@ function preloadInstanceAndSuspendIfNeeded(
534
535
// loaded yet.
535
536
workInProgress . flags |= MaySuspendCommit ;
536
537
537
- // Check if we're rendering at a "non-urgent" priority. This is the same
538
- // check that `useDeferredValue` does to determine whether it needs to
539
- // defer. This is partly for gradual adoption purposes (i.e. shouldn't start
540
- // suspending until you opt in with startTransition or Suspense) but it
541
- // also happens to be the desired behavior for the concrete use cases we've
542
- // thought of so far, like CSS loading, fonts, images, etc.
543
- //
538
+ // preload the instance if necessary. Even if this is an urgent render there
539
+ // could be benefits to preloading early.
540
+ // @TODO we should probably do the preload in begin work
541
+ const requiredTimeout = preloadInstance ( type , props ) ;
542
+
544
543
// We check the "root" render lanes here rather than the "subtree" render
545
544
// because during a retry or offscreen prerender, the "subtree" render
546
545
// lanes may include additional "base" lanes that were deferred during
547
546
// a previous render.
548
- // TODO: We may decide to expose a way to force a fallback even during a
549
- // sync update.
550
547
const rootRenderLanes = getWorkInProgressRootRenderLanes ( ) ;
551
548
if ( ! includesOnlyNonUrgentLanes ( rootRenderLanes ) ) {
552
- // This is an urgent render. Don't suspend or show a fallback. Also,
553
- // there's no need to preload, because we're going to commit this
554
- // synchronously anyway.
555
- // TODO: Could there be benefit to preloading even during a synchronous
556
- // render? The main thread will be blocked until the commit phase, but
557
- // maybe the browser would be able to start loading off thread anyway?
558
- // Likely a micro-optimization either way because typically new content
559
- // is loaded during a transition, not an urgent render.
549
+ // This is an urgent render. If our required timeout is infinite
550
+ // we suspend to allow the nearest fallback to commit instead.
551
+ // if the required timeout is finite we treat it like it is zero
552
+ // and allow the tree to commit as is.
553
+ if ( requiredTimeout === Infinity ) {
554
+ const nearestBoundary = getSuspenseHandler ( ) ;
555
+ if ( nearestBoundary !== null ) {
556
+ // When there is a suspense boundary we can put into fallback we do
557
+ // If not we'll commit without waiting for the required resource
558
+ suspendCommit ( ) ;
559
+ }
560
+ }
560
561
} else {
561
- // Preload the instance
562
- const isReady = preloadInstance ( type , props ) ;
563
- if ( ! isReady ) {
562
+ if ( requiredTimeout ) {
564
563
if ( shouldRemainOnPreviousScreen ( ) ) {
565
564
// It's OK to suspend. Mark the fiber so we know to suspend before the
566
565
// commit phase. Then continue rendering.
@@ -588,12 +587,25 @@ function preloadResourceAndSuspendIfNeeded(
588
587
589
588
workInProgress . flags |= MaySuspendCommit ;
590
589
590
+ const requiredTimeout = preloadResource ( resource ) ;
591
591
const rootRenderLanes = getWorkInProgressRootRenderLanes ( ) ;
592
592
if ( ! includesOnlyNonUrgentLanes ( rootRenderLanes ) ) {
593
- // This is an urgent render. Don't suspend or show a fallback.
593
+ // This is an urgent render. If our required timeout is infinite
594
+ // we suspend to allow the nearest fallback to commit instead.
595
+ // if the required timeout is finite we treat it like it is zero
596
+ // and allow the tree to commit as is.
597
+ if ( requiredTimeout === Infinity ) {
598
+ const nearestBoundary = getSuspenseHandler ( ) ;
599
+ if ( nearestBoundary !== null ) {
600
+ // When there is a suspense boundary we can put into fallback we do
601
+ // If not we'll commit without waiting for the required resource
602
+ suspendCommit ( ) ;
603
+ }
604
+ }
594
605
} else {
595
- const isReady = preloadResource ( resource ) ;
596
- if ( ! isReady ) {
606
+ // This is a transition. If the resource is not ready
607
+ // we can suspend to allow the nearest fallback to commit instead.
608
+ if ( requiredTimeout ) {
597
609
if ( shouldRemainOnPreviousScreen ( ) ) {
598
610
workInProgress . flags |= ShouldSuspendCommit ;
599
611
} else {
0 commit comments