[Solved] Next.js Warning: Text Content Did Not Match

Updated: December 14, 2023 By: Frienzied Flame Post a comment

Developers working with Next.js may have encountered a warning that states: Text content did not match. Server: "ABC", Client: "XYZ". This issue occurs due to a mismatch between the HTML pre-rendered from the server and the HTML rendered during the first render in the browser, a process known as hydration. This article aims to provide a comprehensive understanding of the problem and propose effective solutions.

A Closer Look at the Problem

When you’re working with Next.js applications, the warning about text content not matching can appear when rendering the application. This issue arises due to a discrepancy between the React tree that was pre-rendered from the server and the React tree that was rendered during the initial render in the browser.

The Concept of Hydration

Hydration is essentially the process where React transforms the pre-rendered HTML from the server into a fully interactive application by attaching event handlers. Next.js pre-renders every page on the server by default. This means that Next.js generates HTML for each page in advance, instead of having it all done by client-side JavaScript. Pre-rendering can result in better performance and speed. When a page is loaded by the browser, its JavaScript code runs and makes the page fully interactive. This process is referred to as hydration in React.

Causes of Hydration Errors

Hydration errors can originate from factors such as:

  • Incorrect nesting of HTML tags (e.g., <p> nested in another <p> tag, <div> nested in a <p> tag, <ul> or <ol> nested in a <p> tag)
  • Interactive content that cannot be nested (e.g., <a> nested in a <a> tag, <button> nested in a <button> tag, etc.)
  • Use of checks like typeof window !== 'undefined' in your rendering logic
  • Use of browser-only APIs like window or localStorage in your rendering logic
  • Browser extensions altering the HTML
  • Incorrectly configured CSS-in-JS libraries
  • Incorrectly configured Edge/CDN that tries to modify the HTML response, such as Cloudflare Auto Minify

Solutions to Get Rid of the Issue

There are several strategies that can help address this error. Each solution is explored in detail below.

Using useEffect to Run on the Client Only

One way to prevent a hydration mismatch is to ensure that the component renders the same content server-side as it does during the initial client-side render. You can intentionally render different content on the client with the useEffect hook. Here’s an example:

import { useState, useEffect } from 'react'

export default function App() {
  const [isClient, setIsClient] = useState(false)

  useEffect(() => {
    setIsClient(true)
  }, [])

  return <h1>{isClient ? 'This is never prerendered' : 'Prerendered'}</h1>
}

During React hydration, useEffect is called. This means browser APIs like window are available to use without hydration mismatches.

Disabling SSR on Specific Components

Next.js allows you to disable prerendering on specific components, which can prevent hydration mismatches. Below’s an example:

import dynamic from 'next/dynamic'

const NoSSR = dynamic(() => import('../components/no-ssr'), { ssr: false })

export default function Page() {
  return (
    <div>
      <NoSSR />
    </div>
  )
}

Using suppressHydrationWarning

Sometimes content will inevitably differ between the server and client, such as a timestamp. You can silence the hydration mismatch warning by adding suppressHydrationWarning={true} to the element. Here’s an example:

<time datetime="2024-10-25" suppressHydrationWarning />

Moving State Setting to useEffect

This solution involves moving the setting of the state inside a useEffect. This forces the state to only be set on the client-side, so no mismatches will occur. Let’s see the following example for more clarity:

export default function Home() {
  const cook = new Cookies();
  const [session, setSession] = useState();

  useEffect(() => {
    setSession(cook.get("key"));
  }, []);

  return (
    <div className={styles.container}>
      <button onClick={() => setCookie()}>Save Cookie</button>
      <button onClick={() => deleteCookie()}>Delete Cookie</button>
      {session ? <>I'm in</> : <>I'm out</>}
    </div>
  );
}

Using next/dynamic with { ssr: false }

As an alternate solution, the issue can also be circumvented by dynamically importing the React component with next/dynamic using { ssr: false }, wherever the component is used. This prevents the component from being included on the server, and dynamically loads it on the client-side only.

const Home = dynamic(
  () => import('../components/Home'),
  { ssr: false }
)

Conclusion

In conclusion, hydration errors in Next.js applications can be effectively managed and resolved by understanding the origin of the problem and implementing suitable solutions. The solutions discussed here can help you prevent mismatches between server-side and client-side rendering, thereby overcoming the “text content did not match” warning. Happy coding with Next.js!