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

React 18 bug: Uncaught Error when renderToString on server and hydrateRoot on client for Suspense lazy component #24125

Closed
SuperOleg39 opened this issue Mar 18, 2022 · 17 comments
Labels
React 18 Bug reports, questions, and general feedback about React 18 Resolution: Needs More Information Type: Discussion

Comments

@SuperOleg39
Copy link

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.2
  • renderToString on server and hydrateRoot on client
  • render Suspense + lazy component
  • 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>
  );
};
@SuperOleg39 SuperOleg39 added React 18 Bug reports, questions, and general feedback about React 18 Type: Discussion labels Mar 18, 2022
@lveillard
Copy link

Facing same issue!

@nrgnrg
Copy link

nrgnrg commented Mar 19, 2022

Also facing this issue

@eps1lon
Copy link
Collaborator

eps1lon commented Mar 19, 2022

@SuperOleg39 I tried the linked codesandbox but could not reproduce the issue. Did you forget to freeze the codesandbox and made changes after posting this issue?

Does this reproduce for you 100%? Which browser/OS are you using?

@SuperOleg39
Copy link
Author

@eps1lon I'm found this on MacOS, Chrome 99

Still reproduce the error, when open demo in new window.

Снимок экрана 2022-03-19 в 20 09 56

@SuperOleg39
Copy link
Author

SuperOleg39 commented Mar 19, 2022

Important step - this works only for first page load from the server

@lveillard
Copy link

In my case I'm on Windows and chrome 99
Happens also only on the first page (navigating it's ok) and it happens again when refreshing
I'm using suspense to load dynamically some SVG depending on the selected icon
It was working without any issues some RC versions ago

@sebmarkbage
Copy link
Collaborator

This is using renderToString which 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.lazy has 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.

@sebmarkbage
Copy link
Collaborator

sebmarkbage commented Mar 20, 2022

One thing we could probably due is log a console.log on the server if there were still pending boundaries when using renderToString.

The warning can suggest upgrading to the streaming api in that scenario.

@nghieptiki
Copy link

Same issue in Next.js

next@12.1.1-canary.15
react@rc
react-dom@rc

@SuperOleg39
Copy link
Author

@sebmarkbage thanks for the complete answer!
I understand now the reason for this error, and originally thought that rendering fallback on the server when using renderToString, while React.lazy component is not yet loaded, was a legal feature.

@lveillard
Copy link

Hello @SuperOleg39, would you be able to further detail it a bit? I'm facing the same issue still and i must admit did not get what was your solution.

I'm not doing nothing fancy in my case, as @nghieptiki I'm just using nextjs 12.1.1 with react 18, and lazy loading some svgs, and i was not facing this issue before 🤔

@nghieptiki
Copy link

Hey @lveillard from Next.js vercel/next.js#35564 (comment)

experimental.runtime: 'nodejs' to forces next.js enable streaming rendering to solve this.

@gaearon
Copy link
Collaborator

gaearon commented Mar 25, 2022

I'm just using nextjs 12.1.1 with react 18, and lazy loading some svgs, and i was not facing this issue before 🤔

Can you clarify what you mean by this? lazy was not supported on the server at all before, so how did you do this before?

@SuperOleg39
Copy link
Author

Can you clarify what you mean by this? lazy was not supported on the server at all before, so how did you do this before?

I talking only about react@18 behaviour with renderToString.
As I can see in reactwg/react-18#22, limited Suspense support on the server means that React will render fallback on server, then hydrate it on a client.
And It is works, but with error.

@SuperOleg39
Copy link
Author

SuperOleg39 commented Mar 25, 2022

Can you clarify what you mean by this? lazy was not supported on the server at all before, so how did you do this before?

Oh, sorry, this comment was not for me 🤦

@roggc
Copy link

roggc commented May 14, 2022

is there any way today to do ssr streaming with suspense (data fetching on the server) without having the problem of hydration mismatch? thanks.

for anyone else asking him/herself the same question, here is how, and here is a post with a simple example showing how to do it.

@MEBonham
Copy link

Another user (Windows, Edge, Remix.run) getting this error, but the site is rendering fine; it would be nice to know how to clear the error though.
"If you intended to have the server wait for the suspended component please switch to "renderToPipeableStream" which supports Suspense on the server"
I don't know how to do this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
React 18 Bug reports, questions, and general feedback about React 18 Resolution: Needs More Information Type: Discussion
Projects
None yet
Development

No branches or pull requests

9 participants