@@ -69,7 +69,7 @@ function _assertThisInitialized(self) {
69
69
return self;
70
70
}
71
71
72
- var ReactVersion = "18.3.0-www-classic-dfeb256e ";
72
+ var ReactVersion = "18.3.0-www-classic-e4add0e3 ";
73
73
74
74
var LegacyRoot = 0;
75
75
var ConcurrentRoot = 1;
@@ -543,11 +543,12 @@ var Visibility =
543
543
8192;
544
544
var StoreConsistency =
545
545
/* */
546
- 16384; // It's OK to reuse this bit because these flags are mutually exclusive for
546
+ 16384; // It's OK to reuse these bits because these flags are mutually exclusive for
547
547
// different fiber types. We should really be doing this for as many flags as
548
548
// possible, because we're about to run out of bits.
549
549
550
550
var ScheduleRetry = StoreConsistency;
551
+ var ShouldSuspendCommit = Visibility;
551
552
var LifecycleEffectMask =
552
553
Passive$1 | Update | Callback | Ref | Snapshot | StoreConsistency; // Union of all commit flags (flags with the lifetime of a particular commit)
553
554
@@ -587,8 +588,8 @@ var LayoutStatic =
587
588
var PassiveStatic =
588
589
/* */
589
590
8388608;
590
- var SuspenseyCommit =
591
- /* */
591
+ var MaySuspendCommit =
592
+ /* */
592
593
16777216; // Flag used to identify newly inserted fibers. It isn't reset after commit unlike `Placement`.
593
594
594
595
var PlacementDEV =
@@ -624,7 +625,7 @@ var PassiveMask = Passive$1 | Visibility | ChildDeletion; // Union of tags that
624
625
// This allows certain concepts to persist without recalculating them,
625
626
// e.g. whether a subtree contains passive effects or portals.
626
627
627
- var StaticMask = LayoutStatic | PassiveStatic | RefStatic | SuspenseyCommit ;
628
+ var StaticMask = LayoutStatic | PassiveStatic | RefStatic | MaySuspendCommit ;
628
629
629
630
var ReactCurrentOwner$2 = ReactSharedInternals.ReactCurrentOwner;
630
631
function getNearestMountedFiber(fiber) {
@@ -2934,9 +2935,6 @@ function unhideTextInstance(textInstance, text) {
2934
2935
function getInstanceFromNode(node) {
2935
2936
throw new Error("Not implemented.");
2936
2937
}
2937
- function maySuspendCommit(type, props) {
2938
- return false;
2939
- }
2940
2938
function preloadInstance(type, props) {
2941
2939
// Return true to indicate it's already loaded
2942
2940
return true;
@@ -5590,13 +5588,6 @@ function trackUsedThenable(thenableState, thenable, index) {
5590
5588
}
5591
5589
}
5592
5590
}
5593
- function suspendCommit() {
5594
- // This extra indirection only exists so it can handle passing
5595
- // noopSuspenseyCommitThenable through to throwException.
5596
- // TODO: Factor the thenable check out of throwException
5597
- suspendedThenable = noopSuspenseyCommitThenable;
5598
- throw SuspenseyCommitException;
5599
- } // This is used to track the actual thenable that suspended so it can be
5600
5591
// passed to the rest of the Suspense implementation — which, for historical
5601
5592
// reasons, expects to receive a thenable.
5602
5593
@@ -17697,7 +17688,11 @@ function updateHostComponent(
17697
17688
markUpdate(workInProgress);
17698
17689
}
17699
17690
}
17700
- } // TODO: This should ideally move to begin phase, but currently the instance is
17691
+ } // This function must be called at the very end of the complete phase, because
17692
+ // it might throw to suspend, and if the resource immediately loads, the work
17693
+ // loop will resume rendering as if the work-in-progress completed. So it must
17694
+ // fully complete.
17695
+ // TODO: This should ideally move to begin phase, but currently the instance is
17701
17696
// not created until the complete phase. For our existing use cases, host nodes
17702
17697
// that suspend don't have children, so it doesn't matter. But that might not
17703
17698
// always be true in the future.
@@ -17708,28 +17703,16 @@ function preloadInstanceAndSuspendIfNeeded(
17708
17703
props,
17709
17704
renderLanes
17710
17705
) {
17711
- workInProgress.flags |= SuspenseyCommit; // Check if we're rendering at a "non-urgent" priority. This is the same
17712
- // check that `useDeferredValue` does to determine whether it needs to
17713
- // defer. This is partly for gradual adoption purposes (i.e. shouldn't start
17714
- // suspending until you opt in with startTransition or Suspense) but it
17715
- // also happens to be the desired behavior for the concrete use cases we've
17716
- // thought of so far, like CSS loading, fonts, images, etc.
17717
- // TODO: We may decide to expose a way to force a fallback even during a
17718
- // sync update.
17719
-
17720
- if (!includesOnlyNonUrgentLanes(renderLanes));
17721
- else {
17722
- // Preload the instance
17723
- var isReady = preloadInstance();
17724
-
17725
- if (!isReady) {
17726
- if (shouldRemainOnPreviousScreen());
17727
- else {
17728
- // Trigger a fallback rather than block the render.
17729
- suspendCommit();
17730
- }
17731
- }
17732
- }
17706
+ {
17707
+ // If this flag was set previously, we can remove it. The flag
17708
+ // represents whether this particular set of props might ever need to
17709
+ // suspend. The safest thing to do is for maySuspendCommit to always
17710
+ // return true, but if the renderer is reasonably confident that the
17711
+ // underlying resource won't be evicted, it can return false as a
17712
+ // performance optimization.
17713
+ workInProgress.flags &= ~MaySuspendCommit;
17714
+ return;
17715
+ } // Mark this fiber with a flag. This gets set on all host instances
17733
17716
}
17734
17717
17735
17718
function scheduleRetryEffect(workInProgress, retryQueue) {
@@ -18160,12 +18143,10 @@ function completeWork(current, workInProgress, renderLanes) {
18160
18143
18161
18144
case HostComponent: {
18162
18145
popHostContext(workInProgress);
18163
- var _type = workInProgress.type;
18164
-
18165
- var _maySuspend = maySuspendCommit();
18146
+ var _type2 = workInProgress.type;
18166
18147
18167
18148
if (current !== null && workInProgress.stateNode != null) {
18168
- updateHostComponent(current, workInProgress, _type , newProps);
18149
+ updateHostComponent(current, workInProgress, _type2 , newProps);
18169
18150
18170
18151
if (current.ref !== workInProgress.ref) {
18171
18152
markRef(workInProgress);
@@ -18201,7 +18182,7 @@ function completeWork(current, workInProgress, renderLanes) {
18201
18182
} else {
18202
18183
getRootHostContainer();
18203
18184
18204
- var _instance3 = createInstance(_type , newProps);
18185
+ var _instance3 = createInstance(_type2 , newProps);
18205
18186
18206
18187
appendAllChildren(_instance3, workInProgress);
18207
18188
workInProgress.stateNode = _instance3; // Certain renderers require commit-time effects for initial mount.
@@ -18218,17 +18199,7 @@ function completeWork(current, workInProgress, renderLanes) {
18218
18199
// will resume rendering as if the work-in-progress completed. So it must
18219
18200
// fully complete.
18220
18201
18221
- if (_maySuspend) {
18222
- preloadInstanceAndSuspendIfNeeded(
18223
- workInProgress,
18224
- _type,
18225
- newProps,
18226
- renderLanes
18227
- );
18228
- } else {
18229
- workInProgress.flags &= ~SuspenseyCommit;
18230
- }
18231
-
18202
+ preloadInstanceAndSuspendIfNeeded(workInProgress);
18232
18203
return null;
18233
18204
}
18234
18205
@@ -22603,13 +22574,24 @@ function commitPassiveUnmountEffects(finishedWork) {
22603
22574
setCurrentFiber(finishedWork);
22604
22575
commitPassiveUnmountOnFiber(finishedWork);
22605
22576
resetCurrentFiber();
22606
- }
22577
+ } // If we're inside a brand new tree, or a tree that was already visible, then we
22578
+ // should only suspend host components that have a ShouldSuspendCommit flag.
22579
+ // Components without it haven't changed since the last commit, so we can skip
22580
+ // over those.
22581
+ //
22582
+ // When we enter a tree that is being revealed (going from hidden -> visible),
22583
+ // we need to suspend _any_ component that _may_ suspend. Even if they're
22584
+ // already in the "current" tree. Because their visibility has changed, the
22585
+ // browser may not have prerendered them yet. So we check the MaySuspendCommit
22586
+ // flag instead.
22587
+
22588
+ var suspenseyCommitFlag = ShouldSuspendCommit;
22607
22589
function accumulateSuspenseyCommit(finishedWork) {
22608
22590
accumulateSuspenseyCommitOnFiber(finishedWork);
22609
22591
}
22610
22592
22611
22593
function recursivelyAccumulateSuspenseyCommit(parentFiber) {
22612
- if (parentFiber.subtreeFlags & SuspenseyCommit ) {
22594
+ if (parentFiber.subtreeFlags & suspenseyCommitFlag ) {
22613
22595
var child = parentFiber.child;
22614
22596
22615
22597
while (child !== null) {
@@ -22624,7 +22606,7 @@ function accumulateSuspenseyCommitOnFiber(fiber) {
22624
22606
case HostHoistable: {
22625
22607
recursivelyAccumulateSuspenseyCommit(fiber);
22626
22608
22627
- if (fiber.flags & SuspenseyCommit ) {
22609
+ if (fiber.flags & suspenseyCommitFlag ) {
22628
22610
if (fiber.memoizedState !== null) {
22629
22611
suspendResource();
22630
22612
}
@@ -22640,8 +22622,36 @@ function accumulateSuspenseyCommitOnFiber(fiber) {
22640
22622
}
22641
22623
22642
22624
case HostRoot:
22643
- case HostPortal:
22644
- // eslint-disable-next-line-no-fallthrough
22625
+ case HostPortal: {
22626
+ {
22627
+ recursivelyAccumulateSuspenseyCommit(fiber);
22628
+ }
22629
+
22630
+ break;
22631
+ }
22632
+
22633
+ case OffscreenComponent: {
22634
+ var isHidden = fiber.memoizedState !== null;
22635
+
22636
+ if (isHidden);
22637
+ else {
22638
+ var current = fiber.alternate;
22639
+ var wasHidden = current !== null && current.memoizedState !== null;
22640
+
22641
+ if (wasHidden) {
22642
+ // This tree is being revealed. Visit all newly visible suspensey
22643
+ // instances, even if they're in the current tree.
22644
+ var prevFlags = suspenseyCommitFlag;
22645
+ suspenseyCommitFlag = MaySuspendCommit;
22646
+ recursivelyAccumulateSuspenseyCommit(fiber);
22647
+ suspenseyCommitFlag = prevFlags;
22648
+ } else {
22649
+ recursivelyAccumulateSuspenseyCommit(fiber);
22650
+ }
22651
+ }
22652
+
22653
+ break;
22654
+ }
22645
22655
22646
22656
default: {
22647
22657
recursivelyAccumulateSuspenseyCommit(fiber);
@@ -24707,15 +24717,24 @@ function shouldRemainOnPreviousScreen() {
24707
24717
24708
24718
if (handler === null);
24709
24719
else {
24710
- if (includesOnlyRetries(workInProgressRootRenderLanes)) {
24720
+ if (
24721
+ includesOnlyRetries(workInProgressRootRenderLanes) || // In this context, an OffscreenLane counts as a Retry
24722
+ // TODO: It's become increasingly clear that Retries and Offscreen are
24723
+ // deeply connected. They probably can be unified further.
24724
+ includesSomeLane(workInProgressRootRenderLanes, OffscreenLane)
24725
+ ) {
24711
24726
// During a retry, we can suspend rendering if the nearest Suspense boundary
24712
24727
// is the boundary of the "shell", because we're guaranteed not to block
24713
24728
// any new content from appearing.
24729
+ //
24730
+ // The reason we must check if this is a retry is because it guarantees
24731
+ // that suspending the work loop won't block an actual update, because
24732
+ // retries don't "update" anything; they fill in fallbacks that were left
24733
+ // behind by a previous transition.
24714
24734
return handler === getShellBoundary();
24715
24735
}
24716
24736
} // For all other Lanes besides Transitions and Retries, we should not wait
24717
24737
// for the data to load.
24718
- // TODO: We should wait during Offscreen prerendering, too.
24719
24738
24720
24739
return false;
24721
24740
}
0 commit comments