Fix "Hydration failed ..." Errors in React

Michael La Posta - Dec 24 '23 - - Dev Community

I'm just going to say it: I have a love-hate relationship with programming. Actually, I think it's more of a hate-hate relationship!

I'm really not sure why I keep doing it... I'm probably nuts. 😒

You Know You're Getting Old When...

Back when I started to code almost thirty years ago, when the internet was only starting to be a thing, running into software bugs meant pulling out the various programming books on your shelf and pouring over them for hours on end until you found a solution.

I actually really enjoyed programming back then. I enjoyed the challenge of it, and the feeling of accomplishment when I finally got something to work. I enjoyed the feeling of being able to create something out of nothing.

These days I only develop web applications, not desktop apps, and yet the complexity of these apps seem so much more than what we worked on years back.

The Issue

Case in point, some "hydration failed because the initial ui does not match what was rendered on the server." issues that I just noticed in production on a recent project that were not appearing in development.

Initially I thought it was a Next.JS thing, as the errors were occurring in a Next.JS project I was working on. But after some digging, it looked to be more of a React thing - I just hadn't encountered it in the past while working strictly with React.

What is Hydration?

If you're using React.JS, or one of the frameworks that build on React like Next.JS or Remix.JS, you're probably familiar with the concept of "hydration".

Website hydration isn't unique to the React world though. It simply refers to the process of taking a static HTML page, and after the initial page load, adding in the dynamic elements, like JavaScript, CSS, and other assets.

So the initial page that loads is a static page, and then the rest of the content gets added in after the fact, essentially "hydrating" the page.

The Hydration Error(s)

Hydration Errors

The React docs were giving me 3 vague messages:

Text content does not match server-rendered HTML.
Enter fullscreen mode Exit fullscreen mode
There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.
Enter fullscreen mode Exit fullscreen mode
Hydration failed because the initial UI does not match what was rendered on the server.
Enter fullscreen mode Exit fullscreen mode

I understood what the 1st and 3rd messages were saying, but not why it was happening in the first place.

Possible Causes

So I ran a few Google searches, and there are several different things can cause the above errors.

The most common that I found was around malformed HTML, including unclosed tags, for example:

<div>
  <p>Some text
</div>
Enter fullscreen mode Exit fullscreen mode

Notice the missing closing </p> tag above?

Or, tags that were not properly nested, for example:

<p>
  <div>Some text</div>
</p>
Enter fullscreen mode Exit fullscreen mode

Notice the <div> tag inside the <p> tag above? That's not allowed in HTML because <p> tags can't be the parent of <div> tags!

So I had a quick glance at my code, but couldn't find any malformed HTML.

I then tried a few other unrelated things in my code that I thought might be causing the issue due to a div I had that was pulling external content from a CMS, and only populating the contents after page load, but I was still getting the same errors in production.

I had a bit of a chuckle when I found this post on Stack Overflow.

Specifically this comment in the post:

Can we all agree this error message is worse than useless?! –
Kraken
Oct 27, 2022 at 23:05

That was basically my exact sentiment. I was getting a vague error message, occurring in production only, and therefore no way to chase it down and test it in dev. And the error in the console gave little indication as to where the error was occurring.

So I tried narrowing down my search, and found some posts about how a date rendered on the server using new Date(), and then rendered again on the client, can cause this error.

I realized that made sense since my dev environment is just localhost for both client and server, whereas my production server is running in the cloud, and therefore the client and server are most likely in different timezones.

So I checked my code, and while I wasn't using the Date object directly, I was using the date-fns library. So I wondered if that was where the issue was?

I found this discussion on Vercel's Github, with a bunch of users on the NextJS GitHub talking about using useEffect and useState to ensure the date/time was only rendering post-mount, but that would have likely still needed some timezone finagling, and I didn't want to go down that rabbit hole.

The Solution

Finally, I found another post with a much simpler solution from user eliseumds on August 10th, 2022, which suggested to try adding the suppressHydrationWarning prop to the <time> tag that was displaying the actual date/time.

Solution

So I gave it a try, committed the code, pushed it to production, and BAM! No more errors! Hot Damn!

Now of course, in my case, because the warning was just due to time differences between rendering on the server and client side, adding this suppression prop made sense. If on the other hand you are getting this error, but it doesn't appear to be related to time, then you may want to dig a little deeper at what's causing the error - perhaps malformed HTML, or some other issue.

You can find more details about the suppressHydrationWarning prop in the official React docs.

If you are using the <time> tag in your React app though, and are getting hydration errors, give this a try.

You may just save yourself a few hours of frustration. 😑

Further Reading

If the hydration issues you're having have more to do with some dynamic rendering you're trying to achieve through server-side rendering, you might want to check out this Netlify blog post on the topic for how to get around the issues.

. . . . . . . . . . . . .