Error: hydration failed because the initial UI does not match what was rendered on the server. - How to solve the error in React

Ocassionally, when coding a React app, you'll run into this message: "Error: hydration failed because the initial ui does not match what was rendered on the server.". This happens Server-Side Rendered applications when the HTML that's being generated on the server will not match what the client tries to render.

The message shows a differente between the information sent from the server and what is being hydrated on the client side. If you weren't familiar with the term, "hydration" is a process by which React makes a server-rendered page interactive.

This is a process of attaching event handlers to the existing server-rendered markup and preparing it to respond to user interactions on the page.

Common causes of error for the "hydration failed" message

To identify the issues, you should generally follow these steps:

  1. Identify the component causing the issue: often times, this will involve checking out tool like React Developer Tools or using Jam to get more context for debugging.
  2. Check for differences in the render output between the server and the client: somtimes, the bug might be caused by a different random value, a current date/time or a value from localStorage or elements rendered conditionally based on the environment (e.g. process.env.NODE_ENV)
  3. Look out for async operations: if the rendered output is dependent on async data, this data must be available both on server-side and client-side.
  4. Test server and client independently: an easy way of isolating the problem is rendering the components separately on both the server and the client and comparing the HTML output.
  5. Refactor problematic components: once the issue is identified you can refactor the buggy component and ensure the output is identical on both server-side and client-side.

Quick example of solving the hydration error caused by a random value

Let's say there's a situation where you are using a random number in your component's render function. This will, of course, cause a mismatch between server and client render because the random number will be different each time it's called.

import React from 'react';

class MyComponent extends React.Component {
  render() {
    return (
      <div>
        {Math.random()}
      </div>
    );
  }
}

export default MyComponent;

As you can see, the Math.random() function will return a different number on each render, causing a mismatch between the server and client. To fix this common issue, you could move the random number to the state and only change it as a side-effect after the component has mounted and hydration is complete.

Results after refactoring:

import React from 'react';

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      randomNumber: 0 // initializing with a set value
    };
  }

  componentDidMount() {
    this.setState({
      randomNumber: Math.random() // changing the random number after component is mounted
    });
  }

  render() {
    return (
      <div>
        {this.state.randomNumber}
      </div>
    );
  }
}

export default MyComponent;

In this refactored component, the randomNumber in the state is initialized with a set value (0 in this case), which guarantees that the server and client will render the same output initially.

After the component mounts on the client (i.e., after the componentDidMount lifecycle method is called), the randomNumber is updated to a random value. By this point, hydration has completed and this state change will cause a re-render with the new random value.

Note: If you use React Hooks in functional components, similar logic applies. You would initialize state with a set value using the useState hook and then update the state inside a useEffect hook that runs only after the initial render (equivalent to componentDidMount in a class component).

Dealing with bugs is 💩, but not with Jam.

Capture bugs fast, in a format that thousands of developers love.
Get Jam for free