핵심 요약
"Hydration failed because the server rendered HTML didn't match the client" 에러는 SSR로 만든 HTML과 브라우저의 첫 렌더 결과가 달라서 난다. 원인은 거의 정해져 있다 — 시간/난수, typeof window 분기, 브라우저 확장, 잘못된 태그 중첩. 다른 결과를 만드는 코드를 useEffect로 미루는 게 핵심.
1. 원인별 처방
| 원인 | 해결 |
|---|---|
| new Date()/Math.random()를 렌더에서 사용 | useEffect 안에서 set, 초기엔 placeholder |
| typeof window !== 'undefined' 분기 | useEffect로 미루거나 dynamic import ssr:false |
| localStorage 값으로 첫 렌더 분기 | 마운트 후 읽어 상태 반영 |
| <p> 안에 <div> 등 잘못된 중첩 | 유효한 HTML로 수정 |
2. 클라이언트 전용 값 안전하게 쓰기
const [mounted, setMounted] = useState(false)
useEffect(() => setMounted(true), [])
if (!mounted) return null // 서버·첫 렌더 동일
return <span>{new Date().toLocaleString()}</span>
3. 함정
- Grammarly·번역 확장이 DOM을 건드려 발생하기도 한다 — 시크릿창에서 재현되는지 확인
suppressHydrationWarning은 시간 표시 같은 한 요소에만 쓰고 남발 금지- third-party 위젯은
next/dynamic의ssr:false로 감싸라
자주 묻는 질문
suppressHydrationWarning을 쓰면 해결되나요?
경고만 숨길 뿐 불일치 자체는 남습니다. 시각 표시처럼 의도된 차이가 분명한 단일 요소에만 한정해서 쓰고, 구조적 불일치는 코드로 고쳐야 합니다.
왜 개발 모드에서만 에러가 나나요?
개발 모드가 불일치를 더 엄격히 검사합니다. 프로덕션에서 조용히 넘어가도 실제로는 깜빡임·이벤트 누락이 생기니 고치는 게 맞습니다.

댓글 0