Skip to content

React Hydration Error Explained in 2 Minutes

Published:

React's hydration errors (error #423 and #418) happen when the client render doesn't match the server render. This can happen when using SSR or SSG, often done with Gatsby or Next.js.

Here's one example of a hydration error:

1import React from "react"
2
3const RandomNumberGenerator = () => {
4
5 const randomNumber = Math.random();
6
7 return (
8 <p>Random number: {randomNumber}</p>
9 )
10}
11
12export default RandomNumberGenerator

Can you see what will give a hydration error if you use this as a component?

Spoiler: It is the Math.random function. The reason being is that the random number will be first generated on build time, and then again a random number will be generated on client side when React hydrates. These two numbers have almost no chance to be the same number, as it is random.

As the client side random number doesn't match the random number on server data, React will decide to abandon the server generated DOM data completely and switch to full client side render. React pretty much says "server data doesn't look correct, let's abandon it and do everything from scratch". This results in you losing the benefits of build generation data that Gatsby and Next.js provide, and can often cause a flash of content as the page renders again.

This is what the hydration error is all about, a difference between build data and client data. The fix for this is to find what the difference between server and client data is, and fix that. You should do this by inspecting console errors on your development build, usually React lets you know what the problem is. With the random number generation I would make the number only be generated on client side by using useEffect, that would be one way to solve the issue.

Most common causes for hydration error

Table element is missing <thead> and <tbody>

I have found out that if you don't include the <thead> and <tbody> elements on your table, React will give you a hydration error. Those elements are optional, so normally aren't required in HTML, but they are required when doing SSR / SSG with React. Reason for that is that the two elements will be added by browsers to the DOM if they are missing, but client side rendering doesn't add them to React's shadow DOM. This gives a mismatch of the table data between the static HTML data DOM and client side render, resulting in a hydration error.

Repeating your code won't return the same result

This is the basis of the example code earlier in this article, for an example generating a random number can't be replicated. The code has to return the same thing when it is run on build time and on client side. A fix for this is to either make the code repeatable or make it only run on client side.

You're exporting a variable in an unexpected way

I have found out that exporting a variable (a const in this case) can create a hydration error. I am unsure why, and I can't replicate it on every environment (for an example on this blog post it did work just fine, didn't give errors), but here's the code for it anyway:

This is on an utils file: export const EXAMPLE_ID = 1234567;

Then it is accessed on another file by using this: import { EXAMPLE_ID } from './utils/ids' and <div id={EXAMPLE_ID} />.

This can result on a hydration error. I'm still looking into why it actually happens, but it can happen.

An iframe can give a hydration error? Maybe?

I have heard an iframe to give a hydration error, but perhaps it was just a developer error. The fix for the developer was to use useEffect to load the iframe on client side instead of having it be part of build time.

That could have been just a bandaid to the problem though, I don't think a proper iframe can truly give a hydration error. But maybe it can?