07 / 09

为什么会出现 Hydration Error?

分清 SSR Error 与 Hydration Mismatch,并掌握常见问题的判断方式。

为什么会出现 Hydration Error?

学习目标

理解什么是 SSR Error、什么是 Hydration Error、两者有什么区别,以及为什么 onMounted() 可以避免这些问题。


一、这个知识解决什么问题?

上一章我们已经知道 SSR → 显示 HTML → Hydration 这条流程。

那为什么有时候页面不报错,却会出现:

Hydration completed but contains mismatches.

或者:

Hydration node mismatch

到底什么是 Hydration Error?


二、一起推导

案例一:SSR Error

const width = window.innerWidth

服务器有没有 window没有。 所以服务器直接报错 ReferenceError,连 HTML 都生成不了:

SSR → window → ReferenceError → HTML 都没有返回

Hydration 根本还没有开始,所以这不是 Hydration Error,而是 SSR Error

案例二:真正的 Hydration Error

const width = ref(0)

if (import.meta.client) {
    width.value = window.innerWidth
}
  • 服务器width = 0,生成 <div>0</div>
  • 浏览器:执行 window.innerWidth,得到 1920
  • Vue 想接管:服务器 0 ≠ 浏览器 1920

Vue 在 Hydration 时检测到不一致,报 Hydration Mismatch

这才是真正的 Hydration Error


三、SSR Error 和 Hydration Error 的区别

SSR Error Hydration Error
发生时间 服务器生成 HTML 时 浏览器开始接管 HTML 时
现象 服务器直接崩溃(ReferenceError) 服务器与浏览器结果不一致
HTML 返回了吗 ❌ 没有 ✅ 有
典型例子 直接访问 window 服务器输出 0,浏览器计算出 1920

四、为什么 onMounted() 不会报错?

const width = ref(0)

onMounted(() => {
    width.value = window.innerWidth
})

执行顺序:

服务器 → 生成 HTML(width = 0)
浏览器显示(width = 0)
Hydration(0 = 0,一致!✅)
onMounted() → 修改 width = 1920(正常响应式更新)

第一轮服务器和浏览器都是 0,Hydration 成功。之后 onMounted 修改值是正常响应式更新,已经不是 Hydration,所以不会报错。


五、脑图

SSR Error 与 Hydration Mismatch 判断脑图

以后遇到相关错误,按三个问题依次判断:

  1. 服务器能否执行完成? 如果访问了不存在的 window,会在生成 HTML 前成为 SSR Error。
  2. 服务器是否已经返回 HTML? 没有 HTML 就不可能进入 Hydration。
  3. 客户端首次计算结果是否与服务器一致? 不一致才是 Hydration Mismatch。

onMounted() 能把浏览器专属读取推迟到 Hydration 之后,但页面可能先显示默认值再更新。若该值影响首屏结构,还需考虑 <ClientOnly> 等方案。


六、容易踩坑

❌ window 导致的一定是 Hydration Error

不是。服务器直接执行 window,首先发生的是 SSR Error。

❌ onMounted 属于 SSR

不是。它发生在 Hydration → Mounted 之后,可以安全使用 windowdocumentlocalStorage


一句话记忆

SSR Error 是服务器崩了;Hydration Error 是服务器和浏览器"对不上答案"。