在开发过程中,你可能会遇到 hydration 问题。不要忽视这些警告。
Hydration 不匹配不仅是警告——它们是可能破坏你应用的重要问题的标志:
Vue 会在开发时在浏览器控制台记录 hydration 不匹配的警告:

问题:在服务器端渲染期间使用浏览器特有的 API。
<template>
<div>用户偏好: {{ userTheme }}</div>
</template>
<script setup>
// 这会导致 hydration 不匹配!
// localStorage 在服务器上不存在!
const userTheme = localStorage.getItem('theme') || 'light'
</script>
解决方案:你可以使用 useCookie :
<template>
<div>用户偏好: {{ userTheme }}</div>
</template>
<script setup>
// 这个在服务器和客户端都有效
const userTheme = useCookie('theme', { default: () => 'light' })
</script>
问题:服务器和客户端数据不同。
<template>
<div>{{ Math.random() }}</div>
</template>
解决方案:使用 SSR 友好的状态:
<template>
<div>{{ state }}</div>
</template>
<script setup>
const state = useState('random', () => Math.random())
</script>
问题:在 SSR 期间使用仅客户端的条件。
<template>
<div v-if="window?.innerWidth > 768">
桌面端内容
</div>
</template>
解决方案:使用媒体查询或在客户端处理:
<template>
<div class="responsive-content">
<div class="hidden md:block">桌面端内容</div>
<div class="md:hidden">移动端内容</div>
</div>
</template>
问题:修改 DOM 或依赖浏览器的库(这在标签管理器中非常常见)。
<script setup>
if (import.meta.client) {
const { default: SomeBrowserLibrary } = await import('browser-only-lib')
SomeBrowserLibrary.init()
}
</script>
解决方案:在 hydration 完成后初始化库:
<script setup>
onMounted(async () => {
const { default: SomeBrowserLibrary } = await import('browser-only-lib')
SomeBrowserLibrary.init()
})
</script>
问题:内容根据当前时间变化。
<template>
<div>{{ greeting }}</div>
</template>
<script setup>
const hour = new Date().getHours()
const greeting = hour < 12 ? '早上好' : '下午好'
</script>
解决方案:使用 NuxtTime 组件或客户端处理:
<template>
<div>
<NuxtTime :date="new Date()" format="HH:mm" />
</div>
</template>
<template>
<div>
<ClientOnly>
{{ greeting }}
<template #fallback>
你好!
</template>
</ClientOnly>
</div>
</template>
<script setup>
const greeting = ref('你好!')
onMounted(() => {
const hour = new Date().getHours()
greeting.value = hour < 12 ? '早上好' : '下午好'
})
</script>
useFetch、useAsyncData、useStateClientOnly 组件处理浏览器特有内容onMounted