Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Selective Hydration: Don't suspend if showing fallback #27230

Merged
merged 1 commit into from
Aug 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions packages/react-dom/src/__tests__/ReactDOMFizzServer-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6131,4 +6131,55 @@ describe('ReactDOMFizzServer', () => {
// However, it does error the shell.
expect(fatalErrors).toEqual(['testing postpone']);
});

it(
'a transition that flows into a dehydrated boundary should not suspend ' +
'if the boundary is showing a fallback',
async () => {
let setSearch;
function App() {
const [search, _setSearch] = React.useState('initial query');
setSearch = _setSearch;
return (
<div>
<div>{search}</div>
<div>
<Suspense fallback="Loading...">
<AsyncText text="Async" />
</Suspense>
</div>
</div>
);
}

// Render the initial HTML, which is showing a fallback.
await act(() => {
const {pipe} = renderToPipeableStream(<App />);
pipe(writable);
});

// Start hydrating.
await clientAct(() => {
ReactDOMClient.hydrateRoot(container, <App />);
});
expect(getVisibleChildren(container)).toEqual(
<div>
<div>initial query</div>
<div>Loading...</div>
</div>,
);

// Before the HTML has streamed in, update the query. The part outside
// the fallback should be allowed to finish.
await clientAct(() => {
React.startTransition(() => setSearch('updated query'));
});
expect(getVisibleChildren(container)).toEqual(
<div>
<div>updated query</div>
<div>Loading...</div>
</div>,
);
},
);
});
10 changes: 9 additions & 1 deletion packages/react-reconciler/src/ReactFiberBeginWork.js
Original file line number Diff line number Diff line change
Expand Up @@ -2958,7 +2958,15 @@ function updateDehydratedSuspenseComponent(
// TODO: We should ideally have a sync hydration lane that we can apply to do
// a pass where we hydrate this subtree in place using the previous Context and then
// reapply the update afterwards.
renderDidSuspendDelayIfPossible();
if (isSuspenseInstancePending(suspenseInstance)) {
// This is a dehydrated suspense instance. We don't need to suspend
// because we're already showing a fallback.
// TODO: The Fizz runtime might still stream in completed HTML, out-of-
// band. Should we fix this? There's a version of this bug that happens
// during client rendering, too. Needs more consideration.
} else {
renderDidSuspendDelayIfPossible();
}
return retrySuspenseComponentWithoutHydrating(
current,
workInProgress,
Expand Down