Skip to content

Commit cbca433

Browse files
committed
Revert "Force unwind work loop during selective hydration (#25695)"
We're reverting the stack of changes that this code belongs to in order to unblock the sync to Meta's internal codebase. We will attempt to re-land once the sync is unblocked.
1 parent 8e8495b commit cbca433

File tree

3 files changed

+18
-70
lines changed

3 files changed

+18
-70
lines changed

packages/react-dom/src/__tests__/ReactDOMServerSelectiveHydration-test.internal.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1496,10 +1496,12 @@ describe('ReactDOMServerSelectiveHydration', () => {
14961496
// Start rendering. This will force the first boundary to hydrate
14971497
// by scheduling it at one higher pri than Idle.
14981498
expect(Scheduler).toFlushAndYieldThrough([
1499+
// An update was scheduled to force hydrate the boundary, but React will
1500+
// continue rendering at Idle until the next time React yields. This is
1501+
// fine though because it will switch to the hydration level when it
1502+
// re-enters the work loop.
14991503
'App',
1500-
1501-
// Start hydrating A
1502-
'A',
1504+
'AA',
15031505
]);
15041506

15051507
// Hover over A which (could) schedule at one higher pri than Idle.

packages/react-reconciler/src/ReactFiberBeginWork.js

Lines changed: 6 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -282,14 +282,6 @@ import {
282282

283283
const ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner;
284284

285-
// A special exception that's used to unwind the stack when an update flows
286-
// into a dehydrated boundary.
287-
export const SelectiveHydrationException: mixed = new Error(
288-
"This is not a real error. It's an implementation detail of React's " +
289-
"selective hydration feature. If this leaks into userspace, it's a bug in " +
290-
'React. Please file an issue.',
291-
);
292-
293285
let didReceiveUpdate: boolean = false;
294286

295287
let didWarnAboutBadClass;
@@ -2868,16 +2860,6 @@ function updateDehydratedSuspenseComponent(
28682860
attemptHydrationAtLane,
28692861
eventTime,
28702862
);
2871-
2872-
// Throw a special object that signals to the work loop that it should
2873-
// interrupt the current render.
2874-
//
2875-
// Because we're inside a React-only execution stack, we don't
2876-
// strictly need to throw here — we could instead modify some internal
2877-
// work loop state. But using an exception means we don't need to
2878-
// check for this case on every iteration of the work loop. So doing
2879-
// it this way moves the check out of the fast path.
2880-
throw SelectiveHydrationException;
28812863
} else {
28822864
// We have already tried to ping at a higher priority than we're rendering with
28832865
// so if we got here, we must have failed to hydrate at those levels. We must
@@ -2888,17 +2870,15 @@ function updateDehydratedSuspenseComponent(
28882870
}
28892871
}
28902872

2891-
// If we did not selectively hydrate, we'll continue rendering without
2892-
// hydrating. Mark this tree as suspended to prevent it from committing
2893-
// outside a transition.
2894-
//
2895-
// This path should only happen if the hydration lane already suspended.
2896-
// Currently, it also happens during sync updates because there is no
2897-
// hydration lane for sync updates.
2873+
// If we have scheduled higher pri work above, this will just abort the render
2874+
// since we now have higher priority work. We'll try to infinitely suspend until
2875+
// we yield. TODO: We could probably just force yielding earlier instead.
2876+
renderDidSuspendDelayIfPossible();
2877+
// If we rendered synchronously, we won't yield so have to render something.
2878+
// This will cause us to delete any existing content.
28982879
// TODO: We should ideally have a sync hydration lane that we can apply to do
28992880
// a pass where we hydrate this subtree in place using the previous Context and then
29002881
// reapply the update afterwards.
2901-
renderDidSuspendDelayIfPossible();
29022882
return retrySuspenseComponentWithoutHydrating(
29032883
current,
29042884
workInProgress,

packages/react-reconciler/src/ReactFiberWorkLoop.js

Lines changed: 7 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,6 @@ import {
175175
} from './ReactEventPriorities';
176176
import {requestCurrentTransition, NoTransition} from './ReactFiberTransition';
177177
import {
178-
SelectiveHydrationException,
179178
beginWork as originalBeginWork,
180179
replayFunctionComponent,
181180
} from './ReactFiberBeginWork';
@@ -317,14 +316,13 @@ let workInProgress: Fiber | null = null;
317316
// The lanes we're rendering
318317
let workInProgressRootRenderLanes: Lanes = NoLanes;
319318

320-
opaque type SuspendedReason = 0 | 1 | 2 | 3 | 4 | 5 | 6;
319+
opaque type SuspendedReason = 0 | 1 | 2 | 3 | 4 | 5;
321320
const NotSuspended: SuspendedReason = 0;
322321
const SuspendedOnError: SuspendedReason = 1;
323322
const SuspendedOnData: SuspendedReason = 2;
324323
const SuspendedOnImmediate: SuspendedReason = 3;
325324
const SuspendedOnDeprecatedThrowPromise: SuspendedReason = 4;
326325
const SuspendedAndReadyToUnwind: SuspendedReason = 5;
327-
const SuspendedOnHydration: SuspendedReason = 6;
328326

329327
// When this is true, the work-in-progress fiber just suspended (or errored) and
330328
// we've yet to unwind the stack. In some cases, we may yield to the main thread
@@ -1799,17 +1797,6 @@ function handleThrow(root, thrownValue): void {
17991797
workInProgressSuspendedReason = shouldAttemptToSuspendUntilDataResolves()
18001798
? SuspendedOnData
18011799
: SuspendedOnImmediate;
1802-
} else if (thrownValue === SelectiveHydrationException) {
1803-
// An update flowed into a dehydrated boundary. Before we can apply the
1804-
// update, we need to finish hydrating. Interrupt the work-in-progress
1805-
// render so we can restart at the hydration lane.
1806-
//
1807-
// The ideal implementation would be able to switch contexts without
1808-
// unwinding the current stack.
1809-
//
1810-
// We could name this something more general but as of now it's the only
1811-
// case where we think this should happen.
1812-
workInProgressSuspendedReason = SuspendedOnHydration;
18131800
} else {
18141801
// This is a regular error.
18151802
const isWakeable =
@@ -2051,7 +2038,7 @@ function renderRootSync(root: FiberRoot, lanes: Lanes) {
20512038
markRenderStarted(lanes);
20522039
}
20532040

2054-
outer: do {
2041+
do {
20552042
try {
20562043
if (
20572044
workInProgressSuspendedReason !== NotSuspended &&
@@ -2067,23 +2054,11 @@ function renderRootSync(root: FiberRoot, lanes: Lanes) {
20672054
// function and fork the behavior some other way.
20682055
const unitOfWork = workInProgress;
20692056
const thrownValue = workInProgressThrownValue;
2070-
switch (workInProgressSuspendedReason) {
2071-
case SuspendedOnHydration: {
2072-
// Selective hydration. An update flowed into a dehydrated tree.
2073-
// Interrupt the current render so the work loop can switch to the
2074-
// hydration lane.
2075-
workInProgress = null;
2076-
workInProgressRootExitStatus = RootDidNotComplete;
2077-
break outer;
2078-
}
2079-
default: {
2080-
// Continue with the normal work loop.
2081-
workInProgressSuspendedReason = NotSuspended;
2082-
workInProgressThrownValue = null;
2083-
unwindSuspendedUnitOfWork(unitOfWork, thrownValue);
2084-
break;
2085-
}
2086-
}
2057+
workInProgressSuspendedReason = NotSuspended;
2058+
workInProgressThrownValue = null;
2059+
unwindSuspendedUnitOfWork(unitOfWork, thrownValue);
2060+
2061+
// Continue with the normal work loop.
20872062
}
20882063
workLoopSync();
20892064
break;
@@ -2241,14 +2216,6 @@ function renderRootConcurrent(root: FiberRoot, lanes: Lanes) {
22412216
unwindSuspendedUnitOfWork(unitOfWork, thrownValue);
22422217
break;
22432218
}
2244-
case SuspendedOnHydration: {
2245-
// Selective hydration. An update flowed into a dehydrated tree.
2246-
// Interrupt the current render so the work loop can switch to the
2247-
// hydration lane.
2248-
workInProgress = null;
2249-
workInProgressRootExitStatus = RootDidNotComplete;
2250-
break outer;
2251-
}
22522219
default: {
22532220
throw new Error(
22542221
'Unexpected SuspendedReason. This is a bug in React.',
@@ -3774,7 +3741,6 @@ if (__DEV__ && replayFailedUnitOfWorkWithInvokeGuardedCallback) {
37743741
if (
37753742
didSuspendOrErrorWhileHydratingDEV() ||
37763743
originalError === SuspenseException ||
3777-
originalError === SelectiveHydrationException ||
37783744
(originalError !== null &&
37793745
typeof originalError === 'object' &&
37803746
typeof originalError.then === 'function')

0 commit comments

Comments
 (0)