178
lanesToEventPriority,
179
} from './ReactEventPriorities.new';
180
import {requestCurrentTransition, NoTransition} from './ReactFiberTransition';
181
-import {beginWork as originalBeginWork} from './ReactFiberBeginWork.new';
181
+import {
182
+ SelectiveHydrationException,
183
+ beginWork as originalBeginWork,
184
+} from './ReactFiberBeginWork.new';
185
import {completeWork} from './ReactFiberCompleteWork.new';
186
import {unwindWork, unwindInterruptedWork} from './ReactFiberUnwindWork.new';
187
import {
319
// The lanes we're rendering
320
let workInProgressRootRenderLanes: Lanes = NoLanes;
321
319
-opaque type SuspendedReason = 0 | 1 | 2 | 3 | 4;
322
+opaque type SuspendedReason = 0 | 1 | 2 | 3 | 4 | 5;
323
const NotSuspended: SuspendedReason = 0;
324
const SuspendedOnError: SuspendedReason = 1;
325
const SuspendedOnData: SuspendedReason = 2;
326
const SuspendedOnImmediate: SuspendedReason = 3;
327
const SuspendedAndReadyToUnwind: SuspendedReason = 4;
328
+const SuspendedOnHydration: SuspendedReason = 5;
329
330
// When this is true, the work-in-progress fiber just suspended (or errored) and
331
// we've yet to unwind the stack. In some cases, we may yield to the main thread
1779
workInProgressSuspendedReason = shouldAttemptToSuspendUntilDataResolves()
1780
? SuspendedOnData
1781
: SuspendedOnImmediate;
1782
+ } else if (thrownValue === SelectiveHydrationException) {
1783
+ // An update flowed into a dehydrated boundary. Before we can apply the
1784
+ // update, we need to finish hydrating. Interrupt the work-in-progress
1785
+ // render so we can restart at the hydration lane.
1786
+ //
1787
+ // The ideal implementation would be able to switch contexts without
1788
+ // unwinding the current stack.
1789
+ //
1790
+ // We could name this something more general but as of now it's the only
1791
+ // case where we think this should happen.
1792
+ workInProgressSuspendedThenableState = null;
1793
+ workInProgressSuspendedReason = SuspendedOnHydration;
1794
} else {
1795
// This is a regular error. If something earlier in the component already
1796
// suspended, we must clear the thenable state to unblock the work loop.
1981
return workInProgressRootExitStatus === RootInProgress;
1982
}
1983
1984
+// TODO: Over time, this function and renderRootConcurrent have become more
1985
+// and more similar. Not sure it makes sense to maintain forked paths. Consider
1986
+// unifying them again.
1987
function renderRootSync(root: FiberRoot, lanes: Lanes) {
1988
const prevExecutionContext = executionContext;
1989
executionContext |= RenderContext;
2023
markRenderStarted(lanes);
2024
}
2025
2007
- do {
2026
+ outer: do {
2027
try {
2028
if (
2029
workInProgressSuspendedReason !== NotSuspended &&
2039
// function and fork the behavior some other way.
2040
const unitOfWork = workInProgress;
2041
const thrownValue = workInProgressThrownValue;
2023
- workInProgressSuspendedReason = NotSuspended;
2024
- workInProgressThrownValue = null;
2025
- unwindSuspendedUnitOfWork(unitOfWork, thrownValue);
2026
-
2027
- // Continue with the normal work loop.
2042
+ switch (workInProgressSuspendedReason) {
2043
+ case SuspendedOnHydration: {
2044
+ // Selective hydration. An update flowed into a dehydrated tree.
2045
+ // Interrupt the current render so the work loop can switch to the
2046
+ // hydration lane.
2047
+ workInProgress = null;
2048
+ workInProgressRootExitStatus = RootDidNotComplete;
2049
+ break outer;
2050
+ }
2051
+ default: {
2052
+ // Continue with the normal work loop.
2053
+ workInProgressSuspendedReason = NotSuspended;
2054
+ workInProgressThrownValue = null;
2055
+ unwindSuspendedUnitOfWork(unitOfWork, thrownValue);
2056
+ break;
2057
+ }
2058
+ }
2059
}
2060
workLoopSync();
2061
break;
2191
workInProgressSuspendedReason = SuspendedAndReadyToUnwind;
2192
break outer;
2193
}
2194
+ case SuspendedOnHydration: {
2195
+ // Selective hydration. An update flowed into a dehydrated tree.
2196
+ // Interrupt the current render so the work loop can switch to the
2197
+ // hydration lane.
2198
+ workInProgress = null;
2199
+ workInProgressRootExitStatus = RootDidNotComplete;
2200
+ break outer;
2201
+ }
2202
default: {
2203
workInProgressSuspendedReason = NotSuspended;
2204
workInProgressThrownValue = null;