react: React 18 bug: Uncaught Error when renderToString on server and hydrateRoot on client for Suspense lazy component
Hello!
I get the uncaught error while hydration Suspense component, but except this error, looks like hydration working correctly - fallback changed to lazy component successfully.
Prerequisites
react@18.0.0-rc.2renderToStringon server andhydrateRooton client- render
Suspense+lazycomponent - load page first time
Reproduction
Forked sandbox from Upgrading to React 18 on the server - https://codesandbox.io/s/modest-cdn-we3fvr
Error
Uncaught Error: The server could not finish this Suspense boundary, likely due to an error during server rendering. Switched to client rendering.
at updateDehydratedSuspenseComponent (react-dom.development.js:21341:9)
at updateSuspenseComponent (react-dom.development.js:21005:24)
at beginWork (react-dom.development.js:22225:18)
at beginWork$1 (react-dom.development.js:27022:18)
at performUnitOfWork (react-dom.development.js:26220:16)
at workLoopSync (react-dom.development.js:26134:9)
at renderRootSync (react-dom.development.js:26103:11)
at performConcurrentWorkOnRoot (react-dom.development.js:25419:78)
at workLoop (scheduler.development.js:266:34)
at flushWork (scheduler.development.js:239:14)
Component example
const LazyFallback = () => <div>Loading...</div>;
const LazyBlock = lazy(() => import('../components/Block'));
export const App = () => {
return (
<div>
<Suspense fallback={<LazyFallback />}>
<LazyBlock />
</Suspense>
</div>
);
};
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Reactions: 8
- Comments: 17
Same issue in Next.js
This is using
renderToStringwhich effectively “aborts” any async work that is done since it’s a synchronous API. That gets treated as a “rejection” on the server. The client then considers this to be a “recoverable error” from the server. Which it is because it was a deopt in that case.This case doesn’t happen if
React.lazyhas loaded by the time you render. Like if the server is warmed up. Not sure why it’s so hard to repro in Codesandbox. It probably does some request that warms it up.The solution is to switch to the streaming API on the server. That’s why it’s important to upgrade both the server and the client as part of the React 18 upgrade.
One thing we could probably due is log a
console.logon the server if there were still pending boundaries when using renderToString.The warning can suggest upgrading to the streaming api in that scenario.
Important step - this works only for first page load from the server
Hey @lveillard from Next.js https://github.com/vercel/next.js/issues/35564#issuecomment-1077347776