Hydration Error와 mounted 상태 관리에 대한 설명

KUKJIN LEE • 2일 전 작성
문제 상황
// 문제가 있는 코드
export const FeatureToggles = () => {
const { user } = useAuth();
const isAdmin = user?.email === 'test@gmail.com';
return (
<div>
{isAdmin && <Link>글쓰기</Link>} // 💥 Hydration Error 발생
</div>
);
};
발생 원인
쉽게 얘기하면 순서가 어긋나기 때문에 문제가 발생한다.
-
서버 사이드 렌더링 (SSR)
-
Next.js는 첫 렌더링을 서버에서 수행
-
이때
useAuth()
의 초기 상태는null
또는 빈 상태 -
따라서
isAdmin
은false
가 되어 버튼이 렌더링되지 않음 -
클라이언트 사이드 렌더링
-
브라우저에서 JavaScript가 실행되면서
useAuth()
가 실제 유저 정보를 가져옴 -
isAdmin
이true
가 되어 버튼이 나타남 -
이 차이로 인해 서버와 클라이언트의 렌더링 결과가 불일치
해결 방법
export const FeatureToggles = () => {
const [mounted, setMounted] = useState(false); // 👈 마운트 상태 추가
const { user } = useAuth();
const isAdmin = user?.admin === 'true';
useEffect(() => {
setMounted(true); // 👈 클라이언트에서 마운트 완료 시 상태 변경
}, []);
return (
<div>
{mounted && isAdmin && <Link>글쓰기</Link>} // 👈 마운트 된 후에만 렌더링
</div>
);
};
mounted 상태의 역할
-
초기값
false
-
서버 사이드 렌더링 시에는 항상
false
-
버튼이 렌더링되지 않음
-
서버와 클라이언트의 초기 렌더링이 일치
-
클라이언트에서
true
로 변경 -
useEffect
는 클라이언트에서만 실행 -
컴포넌트가 마운트된 후
mounted
가true
로 변경 -
이후 조건부 렌더링이 정상적으로 동작
장점
-
안정적인 hydration
-
서버와 클라이언트의 초기 렌더링이 일치
-
hydration 에러 방지
-
클라이언트 사이드 로직이 준비된 후에만 조건부 렌더링 실행
단점
-
깜빡임
-
컴포넌트 마운트 후 버튼 표시 가능
-
UX에 영향을 줄 수 있음