Note: the imported Chinese source file available locally was truncated mid-article. This English version is reconstructed from the available source content and the original topic.
Fixing Hydration Failed Errors in React
React server-side rendering helps with page speed and SEO by sending pre-rendered HTML to the browser first. After that, React performs hydration to attach event handlers and turn that static HTML into a live, interactive React tree.
When the HTML generated on the server does not match the HTML produced by the client on the first render, React throws a Hydration Failed error.
What is a hydration error?
In a server-rendered React app, the server outputs HTML first, and the browser receives that HTML before JavaScript takes over. Hydration is the step where React reuses that markup instead of throwing it away and rendering everything from scratch.
If the server output and the initial client render differ, React cannot safely attach to the existing DOM. That mismatch triggers the hydration error.
Why does Hydration Failed happen?
1. Dynamic values produce different output
This is the most common cause. If the rendered markup depends on values such as:
Math.random()Date.now()new Date()windowdocument- browser-only storage or APIs
then the server and client may generate different content.
Bad example:
export default function Page() {
return <div>{Math.random()}</div>
}
The server renders one number, the browser renders another, and hydration fails.
Safer pattern:
'use client'
import { useEffect, useState } from 'react'
export default function Page() {
const [value, setValue] = useState<number | null>(null)
useEffect(() => {
setValue(Math.random())
}, [])
return <div>{value ?? 'Loading...'}</div>
}
2. Async data is not consistent between server and client
If a component depends on data loaded asynchronously, but the server render and the client render do not use the same data snapshot, the resulting markup can differ.
Typical causes:
- fetching data only on the client after the server already rendered placeholder content
- conditionally rendering different states before data is ready
- reading from a cache that is not synchronized between server and client
The fix is to make sure the initial render uses the same data on both sides, or to defer browser-only UI until after mount.
3. Browser-only APIs run too early
Code that accesses window, document, localStorage, sessionStorage, or media queries during render will break SSR assumptions.
Use one of these approaches instead:
- gate the logic inside
useEffect - render the browser-only part only on the client
- in Next.js, use
dynamic(..., { ssr: false })for components that truly cannot render on the server
4. Invalid or unstable markup
Hydration can also fail when the DOM structure itself differs, for example:
- invalid nested HTML
- conditional branches that render different element trees
- keys that change unexpectedly
If the element structure is unstable, React will not be able to hydrate it cleanly.
Practical checklist
When you see a hydration error, check these first:
- Remove
Math.random(),Date.now(), and similar dynamic values from the render path. - Move browser-only logic into
useEffect. - Make sure SSR and the initial client render use the same data.
- Check whether conditional rendering changes the DOM tree between server and client.
- Validate your HTML structure.
Summary
Hydration errors are not random. They almost always mean one thing: the first client render does not match the server-rendered HTML.
In practice, the most common fixes are:
- avoid dynamic values during render
- delay browser-only logic until after mount
- keep the initial data consistent
- make the rendered DOM structure stable
Once you treat hydration as a strict server/client consistency problem, these errors become much easier to debug.