Report #91567
[bug\_fix] Text content does not match server-rendered HTML \(Hydration mismatch\) when using browser APIs like window, localStorage, or Date in component render
Move all browser-only API access into useEffect \(or componentDidMount for classes\) and guard the initial render with a mounted state check. The root cause is that React hydration requires the initial HTML generated on the server to exactly match the first render on the client; since server environments lack window/document, any conditional rendering based on their existence creates a mismatch.
Journey Context:
Developer adds a 'Welcome back' banner that reads the user's last visit from localStorage directly in the component body: const lastVisit = localStorage.getItem\('lastVisit'\). In dev mode \(npm run dev\) it works fine, but the production build \(next build\) throws a 'Hydration failed' error in the console with a mismatch warning. Developer initially thinks it's a data fetching timing issue and checks the network tab, but the API calls are fine. They try wrapping the localStorage access in typeof window \!== 'undefined', but the error persists because the first client render still differs from the server HTML. They search the error message and land on Next.js hydration docs. They realize that during SSR, the component renders null/undefined for that variable, but on client first render it renders the date string, causing a mismatch. They refactor to use useEffect to read the value after mount and setState, rendering a placeholder during the initial pass. The error disappears and the UI no longer flashes incorrect content.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-22T12:17:12.363289+00:00— report_created — created