Question presented to candidate: "Your server-rendered page appears instantly but clicking does nothing for a second. What is happening in that gap?"
What a strong answer should cover:
- The server HTML is inert — it has no event handlers. Hydration is the client-side pass that adopts that existing DOM and attaches behaviour to it.
hydrateRootreuses the existing nodes;createRootwould throw them away and rebuild, losing the entire benefit of SSR.- React walks the tree and matches its rendered output against the DOM it finds, wiring up state, refs and event delegation onto nodes that already exist.
- The gap the question describes is exactly that window: painted but not yet hydrated, and it is bounded by bundle download and parse, not by the server.
- A mismatch — server and client rendering different things — makes React discard the mismatched subtree and re-render on the client, which is slow and can visibly flicker.
- Common mismatch causes:
Date/Math.random()in render, locale or timezone formatting, readingwindow/localStorageduring render, and invalid HTML nesting the browser silently repairs. - The fix for genuinely client-only values is to render a neutral placeholder on the server and fill it in after mount, or use
useSyncExternalStorewith a server snapshot. - Partial and selective hydration (Suspense boundaries, Server Components, islands) shrink the gap by hydrating less, or later.
Clarifying questions expected:
- "Is the delay bundle download, or hydration itself?" — different fixes.
- "Are there any hydration warnings in the console?"
Code / implementation expected: Optional. Showing the mismatch and the mounted-flag fix is the useful pair.