Detailed explanation
Hydration is React’s process of making server-rendered HTML interactive in the browser. The server sends HTML that can display before the application’s JavaScript finishes loading. Once JavaScript runs, React renders the component tree on the client, associates it with the existing DOM, and establishes event handling and component state. Unlike a normal client-only render, hydration aims to reuse existing HTML rather than create the interface from scratch. It combines early content visibility with client-side interactivity, although visible content is not necessarily interactive immediately.
In modern React, hydration starts with hydrateRoot(container, <App />), usually called internally by a framework. React builds its internal component tree and expects the initial client output to match the server output. State initialisers run on the client; React does not automatically recover arbitrary server-side JavaScript state from HTML. Applications therefore commonly provide matching initial data through framework mechanisms or serialised page data. React’s event system generally delegates supported events to the root container rather than attaching a separate native listener to every DOM element. Effects run on the client after the component commits, not during server rendering.
A hydration mismatch occurs when the initial client output differs from the server HTML. Typical causes include timestamps, random values, different data, invalid HTML nesting, and browser-only values. For example, choosing localStorage.theme in the browser but 'light' on the server can produce different initial markup. A safer pattern is useState('light'), followed by useEffect that reads localStorage.getItem('theme') and updates state. Both initial renders then agree, and the preference becomes a normal subsequent update. This can briefly show the default theme; using a cookie available to both server and client can avoid that trade-off.
Interviewers look for the distinction between rendering HTML and activating it, plus an understanding that matching output is a correctness requirement. Mismatches are bugs, not merely harmless warnings: React may leave attributes inconsistent or recover by client-rendering an affected region. suppressHydrationWarning is a narrow escape hatch for unavoidable differences, not a general fix. With Suspense, React can also hydrate different boundaries selectively rather than requiring the whole page to become interactive at once.
Key points to remember
- Hydration reuses server-rendered DOM while establishing React’s client-side component tree and interactivity.
- Use hydrateRoot for server-rendered HTML; use createRoot for a client-only root.
- Server HTML and the initial client render must match, including their initial data.
- Read browser-only preferences in an effect after a matching initial render, or provide consistent server-readable data.
- Hydration mismatches can trigger recovery work or inconsistent output, so fix their underlying causes.
Common mistakes candidates make
- Assuming hydration restores all server-side component state directly from the HTML.
- Using typeof window checks, Date.now(), or random values during rendering without ensuring matching initial output.
- Treating suppressHydrationWarning as a universal fix instead of investigating mismatches.
Likely follow-up questions
How does hydration differ from server-side rendering?
Server-side rendering generates HTML on the server. Hydration runs in the browser and connects React’s component logic and event handling to that HTML.
Why does moving a localStorage read into useEffect prevent a mismatch?
The server and initial client render both use the same default state. The effect reads the browser preference after the component commits, so the resulting change is a normal React update rather than an initial hydration difference.
What is selective hydration?
Selective hydration lets React hydrate Suspense boundaries independently as their required code and content become available. React can prioritise a boundary the user interacts with instead of waiting for every part of the page.
Interview tip: Explain HTML reuse first, then demonstrate a localStorage mismatch and how matching initial state followed by an effect fixes it.
