티스토리 뷰
Nuxt, Next) Hydration completed but contains mismatches. 오류 해결방안
이슈톡톡구리 2025. 4. 7. 17:36Nuxt에서 발생하는 "Hydration completed but contains mismatches." 오류는 서버에서 렌더링된 HTML과 클라이언트에서 렌더링된 HTML이 서로 다를 때 나타나는 문제입니다.
즉, SSR(Server Side Rendering) 과 클라이언트 렌더링(Client Side Rendering) 결과가 일치하지 않을 때 이 오류 메시지를 브라우저 콘솔에서 확인할 수 있습니다.
이 문제를 해결하려면, SSR과 CSR의 출력이 왜 달라졌는지를 파악해야 하며, 일반적으로는 아래와 같은 원인들이 많습니다.
💡 오류 메시지: Hydration completed but contains mismatches.
"Hydration completed but contains mismatches."
Nuxt, Vue (또는 React 등) 프레임워크에서 SSR을 사용할 때, 서버 측 렌더링과 클라이언트 측 렌더링의 결과가 다르면 이 메시지가 출력됩니다.
✨ 주요 원인과 해결 방법
1. 클라이언트 전용 코드가 SSR에도 실행될 때
설명
서버는 DOM이나 window, navigator 객체가 없습니다. 그런데 이런 브라우저 전용 객체를 서버에서 접근하면 hydration mismatch가 발생합니다.
해결 방법
- process.client 또는 <client-only> 컴포넌트를 사용해서 브라우저에서만 렌더링되도록 합니다.
<client-only>
<SomeComponentThatUsesWindow />
</client-only>
또는 JavaScript 코드에서는 다음처럼 조건 분기합니다:
if (process.client) {
// window, localStorage, navigator 사용 가능
}
2. 시간 기반 렌더링의 차이
설명
new Date()나 Date.now() 같은 시간 의존 데이터는 SSR 시점과 CSR 시점이 다를 수 있어서 mismatch를 유발합니다.
해결 방법
- 시간 기반 데이터는 SSR에서 제외하거나 onMounted() 이후에 처리합니다.
- useState나 ref를 통해 상태로 관리하고, 클라이언트에서만 값을 넣습니다.
onMounted(() => {
currentTime.value = new Date().toISOString()
})
3. 랜덤 값, UUID 사용
설명
Math.random() 또는 UUID 생성 등은 SSR과 CSR 결과가 달라지기 쉬운 대표적인 코드입니다.
해결 방법
- 랜덤 값은 클라이언트 전용으로 실행되도록 합니다.
- 가능하다면 서버에서도 같은 시드를 공유하거나, 랜덤이 아닌 다른 방식으로 대체합니다.
<client-only>
<RandomBasedComponent />
</client-only>
4. 조건부 렌더링 구조의 차이
설명
v-if나 v-show 등의 조건이 클라이언트와 서버 간에 다르면 hydration이 깨집니다.
해결 방법
- 조건문에 사용하는 데이터가 서버와 클라이언트에서 동일해야 합니다.
- 조건이 클라이언트에서만 달라질 수 있다면 process.client로 감싸거나 client-only로 감쌉니다.
<template>
<div v-if="process.client && isModalVisible">
클라이언트에서만 보여지는 모달
</div>
</template>
🔍 디버깅을 위한 팁
- Vue Devtools 사용해서 컴포넌트 상태 추적
- console.log(process.server)로 현재 환경 체크
- 브라우저 콘솔의 hydration 관련 경고 메시지 확인
- nuxt.config.js에서 ssr: false로 설정해 CSR로 테스트
export default {
ssr: true, // default
}
🛠 예시 코드로 비교해보기
❌ 문제 있는 코드
<template>
<div>{{ new Date().toLocaleTimeString() }}</div>
</template>
이 코드는 SSR과 CSR 시점의 시간이 달라 mismatch 발생.
✅ 수정된 코드
<template>
<div>{{ time }}</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
const time = ref('')
onMounted(() => {
time.value = new Date().toLocaleTimeString()
})
</script>
🔗 참고자료 및 공식 문서
✅ 마무리 정리
Hydration completed but contains mismatches. 오류는 흔하지만, 원인만 잘 찾으면 쉽게 해결할 수 있는 문제입니다.
Nuxt에서 SSR을 사용할 때는 항상 서버와 클라이언트의 렌더링 결과가 일치해야 한다는 점을 유념하세요.
특히, 브라우저 전용 API, 시간/랜덤값, 조건부 렌더링 등이 일치하지 않을 수 있는 대표적인 요소이므로, 이 부분들을 중점적으로 체크해보세요.
문제를 해결했거나 여전히 발생한다면 관련 코드 일부를 보여주시면 더 구체적인 진단을 도와드릴게요! 😄