React/Next.js Hydration failed 오류 해결
Hydration failed because the initial UI does not match what was rendered on the server
증상
Next.js 앱을 열면 콘솔에 다음과 같은 경고/오류가 표시됩니다.
Hydration failed because the initial UI does not match what was rendered on the server.
화면이 깜빡이거나, 일부 요소가 서버 렌더와 다르게 표시됩니다.
원인
서버에서 만든 HTML과 클라이언트가 처음 그린 결과가 다르기 때문입니다. 흔한 원인:
Date.now(),Math.random()처럼 매 렌더마다 값이 바뀌는 코드window,localStorage등 브라우저 전용 값으로 첫 렌더 분기typeof window !== 'undefined' ? A : B같은 조건부 첫 렌더- 잘못된 HTML 중첩(예:
<p>안에<div>)
// ✕ 서버와 클라이언트 결과가 달라짐
function Clock() {
return <span>{new Date().toLocaleTimeString()}</span>;
}
해결
1) 클라이언트에서만 바뀌는 값은 마운트 후에 반영
import { useEffect, useState } from 'react';
function Clock() {
const [time, setTime] = useState('');
useEffect(() => {
setTime(new Date().toLocaleTimeString()); // 마운트 후 실행 → 서버 HTML과 충돌 없음
}, []);
return <span>{time}</span>;
}
2) 브라우저 전용 컴포넌트는 동적 import로 SSR 끄기
import dynamic from 'next/dynamic';
const ClientOnly = dynamic(() => import('./ClientOnly'), { ssr: false });
3) HTML 중첩 규칙 지키기
<p> 안에 블록 요소(<div>, <ul>)를 넣지 않습니다. 브라우저가 자동으로 태그를 닫아 구조가 달라지면 hydration이 깨집니다.
규칙: 첫 렌더(서버)와 첫 렌더(클라이언트)는 100% 같아야 합니다. "다를 수밖에 없는 것"은
useEffect이후로 미루세요.