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

Bug: React 18 is not able to suppressHydrationWarning #25627

Closed
justin-calleja opened this issue Nov 3, 2022 · 10 comments
Closed

Bug: React 18 is not able to suppressHydrationWarning #25627

justin-calleja opened this issue Nov 3, 2022 · 10 comments
Labels
Component: Server Rendering Resolution: Wontfix Status: Unconfirmed A potential issue that we haven't yet confirmed as a bug

Comments

@justin-calleja
Copy link

justin-calleja commented Nov 3, 2022

React version: 18.2.0

Steps To Reproduce

  1. clone https://github.com/justin-calleja/suppress-hydration-warning
  2. cd to both shw-17 and shw-18 directories and install with: yarn
  3. Run yarn dev to run both nextjs servers on different ports.
  4. Go to the one running React 17 - you should not get the hydration warning.
  5. Go to the one running React 18 - you should get the hydration warning.

Link to code example: https://github.com/justin-calleja/suppress-hydration-warning

Was using Node v18.10.0 when I made the example.

The current behavior

Using React 18, I cannot avoid getting the hydration warning when running my app with the nextjs dev server.

The expected behavior

Just like using React 17, I would like to use React 18 and suppress this warning when building an SPA only page with nextjs using nextjs just for it's build setup and maybe api features (node server).

Thank you

@justin-calleja justin-calleja added the Status: Unconfirmed A potential issue that we haven't yet confirmed as a bug label Nov 3, 2022
@eps1lon eps1lon changed the title Bug: Comparing same app with React 17 v.s. 18. React 18 is not able to suppressHydrationWarnings Bug: React 18 is not able to suppressHydrationWarning Nov 4, 2022
@eps1lon
Copy link
Collaborator

eps1lon commented Nov 4, 2022

Smaller repro without Next.js: https://codesandbox.io/s/react-18-suppresshydrationwarning-8zglen?file=/src/index.js:153-177
Original behavior in 17: https://codesandbox.io/s/react-17-suppresshydrationwarning-forked-w6mv5v

@MaltesBytes

This comment was marked as spam.

@quintenvk
Copy link

Facing this issue as well here; is this still on the radar?

@gaearon gaearon removed the Type: Bug label Feb 24, 2023
@gaearon
Copy link
Collaborator

gaearon commented Feb 24, 2023

I do not believe there is a bug here. The old behavior was a bug.

suppressHydrationWarning is only supposed to suppress the error about the difference in attributes or text content of an element (for example, for a timestamp). It does not let you pass arbitrarily different children or trees.

Your original motivating example is not a supported use case. If you want to render something on the client only, you can use one of these options:

  • Add isMounted state that's initialized to false, render isMounted ? <div /> : nulll both on the client and server, but set isMounted to true in useEffect.
  • Or if (typeof window === 'undefined') throw Error('This component is client-only') on the server only and wrap a <Suspense fallback={<Spinner />}> boundary around your component. The server will emit the fallback, and on the client it will retry rendering (which will succeed). This might seem a bit unusual, but it's the canonical way to render client-only content. You can suppress the error you've thrown from the console in onRecoverableError handler in your hydrateRoot options.

@justin-calleja
Copy link
Author

suppressHydrationWarning is only supposed to suppress the error about the difference in attributes or text content of an element (for example, for a timestamp). It does not let you pass arbitrarily different children or trees.

Was not aware of this. In my case, I was able to switch over to Vite for the app in question which didn't need Next.js features. Maybe mixing the 2 would be another approach for a path in Next.js that needs to be SPA - for anyone with a similar issue. Or of course, look into options suggested by @gaearon #25627 (comment)

@gaearon
Copy link
Collaborator

gaearon commented Feb 24, 2023

Using one of the options I suggested should be a lot easier than mixing the two.

@justin-calleja
Copy link
Author

@gaearon I'm sure you're right if use case is such that moving away from Next.js is painful. In my case - I was only using Next.js to quickly get started building an SPA (with maybe the "peace of mind" of knowing I can switch over to some SSR pages in the future if I want to).

In case of stuck with Next.js - I would first try out your suggestions to get the SPA to work. What I meant by "mixing" the two - is actually not that hard in my opinion. In fact, my use case was gradually replacing SSR content from a Golang server - gradually moving it over to serving API only and drive the FE via the SPA. This is similar if you had Next.js as the server instead of Go. I simply built the SPA in another project - relying on dev time proxying or mocking for development - and then bundle up and serve the SPA under it's own path behind a reverse proxy.

I think this might work well but it depends on use case. For e.g. I can see how - if you already have React components being used in Next.js when doing SSR - you might want to re-use them in the SPA. That would necessitate sharing of the components - which is obviously doable - but more work to do. So basically, from what I understood - preventing SSR for your SPA in Next.js via suggested approaches would be a simpler solution in this case.

@justin-calleja
Copy link
Author

@gaearon thanks for answering btw. Although not a problem I'm facing any more - it's good to know what official approach is i.e. that the warning is not a bug and should prevent SSR.

@JohnLouderback
Copy link

@gaearon We have the opposite problem in our codebase. We have breakpoints components to control conditional rendering. Because, on the server-side, we don't know what the breakpoint is on the client, we render all possible trees on the server and allow CSS to naturally hide or show them. However, on the client, there's no reason to render large sub-trees of components that don't apply to the current breakpoint - which we can determine during hydration on the client - so why waste cycles waiting for useEffect?

@jonathandewitt-dev
Copy link

jonathandewitt-dev commented Jun 9, 2023

suppressHydrationWarning is only supposed to suppress the error about the difference in attributes or text content of an element (for example, for a timestamp). It does not let you pass arbitrarily different children or trees.

Had to do some digging to stumble on this one. I think this issue better represents my problem than this other one, but this may serve as a lead for investigating that other issue.

If you want to render something on the client only, you can use one of these options

The issue with the suggested solutions here is that they aren't really applicable to declarative shadow DOM. Browsers automatically remove <template shadowrootmode="open"> tags when the HTML is parsed, so it will never match the server. The suggestion to make it client-only negates the goal of rendering DSD on the server. There's already an open issue about this, but if you have any suggestions for a workaround in the meantime, I'm all ears!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Component: Server Rendering Resolution: Wontfix Status: Unconfirmed A potential issue that we haven't yet confirmed as a bug
Projects
None yet
Development

No branches or pull requests

7 participants