@@ -69,7 +69,7 @@ function _assertThisInitialized(self) {
69
69
return self;
70
70
}
71
71
72
- var ReactVersion = "18.3.0-www-classic-84a0a171e-20221214 ";
72
+ var ReactVersion = "18.3.0-www-classic-7efa9e597-20221215 ";
73
73
74
74
var LegacyRoot = 0;
75
75
var ConcurrentRoot = 1;
@@ -12716,7 +12716,14 @@ function getMarkerInstances() {
12716
12716
return null;
12717
12717
}
12718
12718
12719
- var ReactCurrentOwner$1 = ReactSharedInternals.ReactCurrentOwner;
12719
+ var ReactCurrentOwner$1 = ReactSharedInternals.ReactCurrentOwner; // A special exception that's used to unwind the stack when an update flows
12720
+ // into a dehydrated boundary.
12721
+
12722
+ var SelectiveHydrationException = new Error(
12723
+ "This is not a real error. It's an implementation detail of React's " +
12724
+ "selective hydration feature. If this leaks into userspace, it's a bug in " +
12725
+ "React. Please file an issue."
12726
+ );
12720
12727
var didReceiveUpdate = false;
12721
12728
var didWarnAboutBadClass;
12722
12729
var didWarnAboutModulePatternComponent;
@@ -14911,18 +14918,29 @@ function updateDehydratedSuspenseComponent(
14911
14918
current,
14912
14919
attemptHydrationAtLane,
14913
14920
eventTime
14914
- );
14915
- }
14916
- } // If we have scheduled higher pri work above, this will just abort the render
14917
- // since we now have higher priority work. We'll try to infinitely suspend until
14918
- // we yield. TODO: We could probably just force yielding earlier instead.
14921
+ ); // Throw a special object that signals to the work loop that it should
14922
+ // interrupt the current render.
14923
+ //
14924
+ // Because we're inside a React-only execution stack, we don't
14925
+ // strictly need to throw here — we could instead modify some internal
14926
+ // work loop state. But using an exception means we don't need to
14927
+ // check for this case on every iteration of the work loop. So doing
14928
+ // it this way moves the check out of the fast path.
14919
14929
14920
- renderDidSuspendDelayIfPossible(); // If we rendered synchronously, we won't yield so have to render something.
14921
- // This will cause us to delete any existing content.
14930
+ throw SelectiveHydrationException;
14931
+ }
14932
+ } // If we did not selectively hydrate, we'll continue rendering without
14933
+ // hydrating. Mark this tree as suspended to prevent it from committing
14934
+ // outside a transition.
14935
+ //
14936
+ // This path should only happen if the hydration lane already suspended.
14937
+ // Currently, it also happens during sync updates because there is no
14938
+ // hydration lane for sync updates.
14922
14939
// TODO: We should ideally have a sync hydration lane that we can apply to do
14923
14940
// a pass where we hydrate this subtree in place using the previous Context and then
14924
14941
// reapply the update afterwards.
14925
14942
14943
+ renderDidSuspendDelayIfPossible();
14926
14944
return retrySuspenseComponentWithoutHydrating(
14927
14945
current,
14928
14946
workInProgress,
@@ -22920,7 +22938,8 @@ var SuspendedOnError = 1;
22920
22938
var SuspendedOnData = 2;
22921
22939
var SuspendedOnImmediate = 3;
22922
22940
var SuspendedOnDeprecatedThrowPromise = 4;
22923
- var SuspendedAndReadyToUnwind = 5; // When this is true, the work-in-progress fiber just suspended (or errored) and
22941
+ var SuspendedAndReadyToUnwind = 5;
22942
+ var SuspendedOnHydration = 6; // When this is true, the work-in-progress fiber just suspended (or errored) and
22924
22943
// we've yet to unwind the stack. In some cases, we may yield to the main thread
22925
22944
// after this happens. If the fiber is pinged before we resume, we can retry
22926
22945
// immediately instead of unwinding the stack.
@@ -24114,6 +24133,30 @@ function getRenderLanes() {
24114
24133
return renderLanes$1;
24115
24134
}
24116
24135
24136
+ function resetWorkInProgressStack() {
24137
+ if (workInProgress === null) return;
24138
+ var interruptedWork;
24139
+
24140
+ if (workInProgressSuspendedReason === NotSuspended) {
24141
+ // Normal case. Work-in-progress hasn't started yet. Unwind all
24142
+ // its parents.
24143
+ interruptedWork = workInProgress.return;
24144
+ } else {
24145
+ // Work-in-progress is in suspended state. Reset the work loop and unwind
24146
+ // both the suspended fiber and all its parents.
24147
+ resetSuspendedWorkLoopOnUnwind();
24148
+ interruptedWork = workInProgress;
24149
+ }
24150
+
24151
+ while (interruptedWork !== null) {
24152
+ var current = interruptedWork.alternate;
24153
+ unwindInterruptedWork(current, interruptedWork);
24154
+ interruptedWork = interruptedWork.return;
24155
+ }
24156
+
24157
+ workInProgress = null;
24158
+ }
24159
+
24117
24160
function prepareFreshStack(root, lanes) {
24118
24161
root.finishedWork = null;
24119
24162
root.finishedLanes = NoLanes;
@@ -24127,27 +24170,7 @@ function prepareFreshStack(root, lanes) {
24127
24170
cancelTimeout(timeoutHandle);
24128
24171
}
24129
24172
24130
- if (workInProgress !== null) {
24131
- var interruptedWork;
24132
-
24133
- if (workInProgressSuspendedReason === NotSuspended) {
24134
- // Normal case. Work-in-progress hasn't started yet. Unwind all
24135
- // its parents.
24136
- interruptedWork = workInProgress.return;
24137
- } else {
24138
- // Work-in-progress is in suspended state. Reset the work loop and unwind
24139
- // both the suspended fiber and all its parents.
24140
- resetSuspendedWorkLoopOnUnwind();
24141
- interruptedWork = workInProgress;
24142
- }
24143
-
24144
- while (interruptedWork !== null) {
24145
- var current = interruptedWork.alternate;
24146
- unwindInterruptedWork(current, interruptedWork);
24147
- interruptedWork = interruptedWork.return;
24148
- }
24149
- }
24150
-
24173
+ resetWorkInProgressStack();
24151
24174
workInProgressRoot = root;
24152
24175
var rootWorkInProgress = createWorkInProgress(root.current, null);
24153
24176
workInProgress = rootWorkInProgress;
@@ -24206,6 +24229,17 @@ function handleThrow(root, thrownValue) {
24206
24229
workInProgressSuspendedReason = shouldAttemptToSuspendUntilDataResolves()
24207
24230
? SuspendedOnData
24208
24231
: SuspendedOnImmediate;
24232
+ } else if (thrownValue === SelectiveHydrationException) {
24233
+ // An update flowed into a dehydrated boundary. Before we can apply the
24234
+ // update, we need to finish hydrating. Interrupt the work-in-progress
24235
+ // render so we can restart at the hydration lane.
24236
+ //
24237
+ // The ideal implementation would be able to switch contexts without
24238
+ // unwinding the current stack.
24239
+ //
24240
+ // We could name this something more general but as of now it's the only
24241
+ // case where we think this should happen.
24242
+ workInProgressSuspendedReason = SuspendedOnHydration;
24209
24243
} else {
24210
24244
// This is a regular error.
24211
24245
var isWakeable =
@@ -24431,7 +24465,7 @@ function renderRootSync(root, lanes) {
24431
24465
markRenderStarted(lanes);
24432
24466
}
24433
24467
24434
- do {
24468
+ outer: do {
24435
24469
try {
24436
24470
if (
24437
24471
workInProgressSuspendedReason !== NotSuspended &&
@@ -24447,9 +24481,25 @@ function renderRootSync(root, lanes) {
24447
24481
// function and fork the behavior some other way.
24448
24482
var unitOfWork = workInProgress;
24449
24483
var thrownValue = workInProgressThrownValue;
24450
- workInProgressSuspendedReason = NotSuspended;
24451
- workInProgressThrownValue = null;
24452
- unwindSuspendedUnitOfWork(unitOfWork, thrownValue); // Continue with the normal work loop.
24484
+
24485
+ switch (workInProgressSuspendedReason) {
24486
+ case SuspendedOnHydration: {
24487
+ // Selective hydration. An update flowed into a dehydrated tree.
24488
+ // Interrupt the current render so the work loop can switch to the
24489
+ // hydration lane.
24490
+ resetWorkInProgressStack();
24491
+ workInProgressRootExitStatus = RootDidNotComplete;
24492
+ break outer;
24493
+ }
24494
+
24495
+ default: {
24496
+ // Continue with the normal work loop.
24497
+ workInProgressSuspendedReason = NotSuspended;
24498
+ workInProgressThrownValue = null;
24499
+ unwindSuspendedUnitOfWork(unitOfWork, thrownValue);
24500
+ break;
24501
+ }
24502
+ }
24453
24503
}
24454
24504
24455
24505
workLoopSync();
@@ -24614,6 +24664,15 @@ function renderRootConcurrent(root, lanes) {
24614
24664
break;
24615
24665
}
24616
24666
24667
+ case SuspendedOnHydration: {
24668
+ // Selective hydration. An update flowed into a dehydrated tree.
24669
+ // Interrupt the current render so the work loop can switch to the
24670
+ // hydration lane.
24671
+ resetWorkInProgressStack();
24672
+ workInProgressRootExitStatus = RootDidNotComplete;
24673
+ break outer;
24674
+ }
24675
+
24617
24676
default: {
24618
24677
throw new Error(
24619
24678
"Unexpected SuspendedReason. This is a bug in React."
@@ -25983,6 +26042,7 @@ if (replayFailedUnitOfWorkWithInvokeGuardedCallback) {
25983
26042
if (
25984
26043
didSuspendOrErrorWhileHydratingDEV() ||
25985
26044
originalError === SuspenseException ||
26045
+ originalError === SelectiveHydrationException ||
25986
26046
(originalError !== null &&
25987
26047
typeof originalError === "object" &&
25988
26048
typeof originalError.then === "function")
0 commit comments