코딩일상

[next.js] Hydration mismatch 에러(사이드 프로젝트 진행하며 ) 본문

기록/Troubleshooting

[next.js] Hydration mismatch 에러(사이드 프로젝트 진행하며 )

solutionMan 2025. 1. 1. 17:46
반응형

개요

next.js 를 통해서 개인 프로젝트를 진행하던중

Hydration mismatch 라는 이슈를 마주하게 되었다.


 

하이드레이션이란?


하이드레이션 비유를

🧊 얼음 큐브(서버의 HTML) → 💧 물(상호작용 가능한 웹페이지)

서버에서 보내준 HTML은 '얼음 큐브’이다
모양은 갖추어져 있지만, 딱딱하고 변화가 없다.
 
이 얼음 큐브가 브라우저에서 
'물'이 되어야 사용자와 상호작용할 수 있다.
이렇게 얼음을 물로 만드는 과정이 바로 '하이드레이션'


왜  하이드레이션이 필요??


1. 빠른 초기 로딩
- 서버가 미리 HTML을 만들어서 보내줌
- 사용자가 빨리 콘텐츠를 볼 수 있음

2. 검색 엔진 최적화(SEO)
- 검색 엔진이 콘텐츠를 잘 읽을 수 있음
- 더 나은 검색 결과 노출

3. 사용자 경험
- 초기 화면이 깜빡이지 않음
- 자연스러운 페이지 전환


하이드레이션 에러는 언제 발생

 

1. 서버와 클라이언트가 다른 그림을 그릴 때
 // ❌
javascript
const randomNumber = Math.random();

 // ✅
const [randomNumber, setRandomNumber] = useState(0);
useEffect(() => {
setRandomNumber(Math.random());
}, []);

2. 브라우저에만 있는 기능을 바로 사용할 때
 // ❌
const width = window.innerWidth;

// ✅
const [width, setWidth] = useState(0);
useEffect(() => {
setWidth(window.innerWidth);
}, []);
 
3. 날짜나 시간을 직접 사용할 때
// ❌
const now = new Date().toLocaleString();

// ✅
const [now, setNow] = useState("");
useEffect(() => {
setNow(new Date().toLocaleString());
}, []);


해결 방법


1. 정적 초기값 사용하기
const [value, setValue] = useState("");

 

2. useEffect 활용하기

useEffect(() => {
// 여기에 브라우저 관련 코드 작성
}, []);

 

3. 컴포넌트 분리하기
// 서버 컴포넌트
function Page() {
return <ClientComponent />;
}

// 클라이언트 컴포넌트
"use client";
function ClientComponent() {
// 브라우저 기능 사용
}

정리


하이드레이션은:
1. 서버의 HTML을 브라우저에서 동작하는 React 앱으로 전환하는 과정
2. SEO와 초기 로딩 속도를 위해 필요
3. 서버와 클라이언트의 결과물이 일치해야 함

마무리

하이드레이션은 어려워 보이지만, 
결국은 '얼음을 물로 만드는 과정'
기본 원칙만 잘 지키면 쉽게 해결할 수 있답니다!
 
 

추가

1 suppressHydrationWarning 사용
특정 컴포넌트에서 하이드레이션 불일치를 허용하고 싶을 때 사용해요.

 

// ✅ 시간을 보여주는 컴포넌트
function TimeDisplay() {
return (
<div suppressHydrationWarning>
현재 시각: {new Date().toLocaleTimeString()}
</div>
);
}

 

주의:
- 하이드레이션 경고만 숨기는 것
- 실제 문제를 해결하는것은 아님
- 정말 필요한 경우에만 사용

 

2 useExternalStore

 

외부 데이터나 브라우저 API를 사용할 때 더 안전한 방법이에요.

 

import { useExternalStore } from 'react';


// ✅ 브라우저 창 크기를 안전하게 구독
function WindowSize() {
const width = useExternalStore(
// 구독 함수
(callback) => {
window.addEventListener('resize', callback);
return () => window.removeEventListener('resize', callback);
},
// 현재 상태를 가져오는 함수
() => window.innerWidth,
// 서버 상태를 가져오는 함수 (선택적)
() => 1024 // 기본값
);


return <div>창 너비: {width}px</div>;
}

 

장점:
- 서버와 클라이언트의 상태를 명확하게 관리
- 외부 데이터 변화를 자동으로 감지
- 하이드레이션 불일치 방지

 

어떤 해결 방법을 선택해야 하나!!

1. 일반적인 경우
- 정적 초기값 + useEffect 조합이 가장 안전

 

2. 시간이나 날짜 표
- suppressHydrationWarning이 간단한 해결책

 

3. 외부 데이터나 브라우저 API
- useExternalStore가 가장 안정적이에요

 

4. 복잡한 컴포넌트
- 서버/클라이언트 컴포넌트 분리가 좋아요

참고

 

Text content does not match server-rendered HTML

Using App Router Features available in /app

nextjs.org

 

 

React의 hydration mismatch 알아보기 – 화해 블로그 | 기술 블로그

React의 hydration mismatch 알아보기 화해는 에러 트래킹 서비스인 Sentry를 사용하고 있는데요. 지난해 Next.js의 static export로 배포한 이벤트 페이지에서 hydration mismatch 에러가 쌓이기 시작했습니다.

blog.hwahae.co.kr

 

 

어쩔 수 없는 hydration mismatch를 useEffect없이 해결하기

서론

medium.com

반응형
Comments