首页 > 基础资料 博客日记

为什么 SSR 一定会有 hydration mismatch?

2026-04-29 16:30:02基础资料围观1

本篇文章分享为什么 SSR 一定会有 hydration mismatch?,对你有帮助的话记得收藏一下,看极客资料网收获更多编程知识

之前说到过 Hydration Mismatch 原理,今天来说说 为什么从设计上,它就无法完全避免

一、先把问题还原到最本质

SSR 做了两件事:

  1. 服务端生成 HTML
  2. 客户端接管(Hydration)

Hydration 的本质是:

在不重建 DOM 的情况下,让 JS 接管已有 HTML (原理详解)

这里有一个隐含前提

客户端“重新执行一遍渲染逻辑”,并且结果必须和服务端完全一致 (原理详解)


二、关键矛盾:同一份代码,在两个环境执行

这是问题的根源。

SSR 架构本质是:

同一套组件逻辑
在两个环境执行:
- Node(服务端)
- Browser(客户端)

问题在于:

这两个环境永远不可能完全一致


三、用一个最简单的例子说明

<span>{new Date().getMilliseconds()}</span>

服务端输出:

<span>123</span>

客户端执行:

<span>167</span>

结果:

不一致 → mismatch (Vite-plugin-ssr)
所以推导出一个结论:只要渲染依赖“运行时”,就必然存在不一致的可能


四、为什么“不一致”是必然的

从几个维度拆开看:


1. 时间是不一致的

Date.now()
new Date()
  • 服务端时间 ≠ 客户端时间
  • 网络延迟会放大差异

结论:

只要用时间,就有 mismatch 风险 (Vite-plugin-ssr)


2. 环境是不一致的

服务端没有:

window
document
localStorage

客户端有,典型代码:

if (typeof window !== 'undefined') {
  // client logic
}

结果:

  • 服务端渲染 A
  • 客户端渲染 B

直接 mismatch


3. 状态是不一致的

例如:

if (localStorage.getItem('token')) {
  return <Home />
} else {
  return <Login />
}

服务端:

  • 没有 localStorage → Login

客户端:

  • 有 token → Home

结果:

DOM 完全不同


4. 随机性是不一致的

Math.random()
uuid()

服务端生成一套
客户端再生成一套

结论:

不可能一致


5. 执行顺序是不一致的

例如:

  • async 数据
  • 并发渲染
  • 不稳定 ID 生成

再次重复一开始提到的前提:SSR 本质是“重复计算”,而重复计算无法保证一致性


五、为什么框架“必须要求一致”?

问题来了:

为什么一定要一致?

因为 Hydration 的优化前提是:

复用已有 DOM
而不是重新创建

如果不一致:

框架只能:

  1. 丢弃 DOM
  2. 重新渲染

这会导致:


一个更本质的矛盾

SSR 想要:

提前生成 HTML(提高首屏)

但 Hydration 需要:

再执行一遍渲染逻辑

这本身就是:

一次“重复执行系统”

而所有重复执行系统都有一个问题:

一致性无法保证


六、工程上怎么“缓解”,但不是“解决”(mismatch 只能减少,无法彻底消灭)

常见手段:

1. 保证初始数据一致

// server 计算
const data = fetch()

// 注入 HTML
window.__INITIAL_DATA__ = data

2. 延迟客户端逻辑

useEffect(() => {
  // client only
}, [])

3. 避免不确定性

不要在 render 中用:

  • Date
  • Math.random
  • 浏览器 API

4. 架构层优化

例如:

  • Islands Architecture
  • Partial Hydration

本质是:

减少需要 hydration 的范围


七、讨论一下 Islands:为什么这个架构本质是在“逃避 hydration”

先看传统 SSR 流程:

Server Render HTML
        ↓
Browser 接收 HTML
        ↓
整页 Hydration
        ↓
页面可交互

问题在于:

页面里很多内容其实根本不需要交互。

例如一个电商详情页:

  • 商品标题
  • 商品描述
  • banner
  • 评论文本
  • footer

这些内容:

  • 需要 SEO
  • 需要首屏展示
  • 但不需要 JS 接管

然而传统 SSR 会做什么?

即使这些内容完全静态,也要执行 hydration。

也就是说:

静态内容 + 动态内容
全部进入 hydration

这就带来两个问题:

1. 不必要的 JS 执行

例如页面结构:

<div>
  Header
  ProductInfo
  Comments
  BuyButton
  Footer
</div>

真正需要交互的可能只有:

BuyButton

但传统 hydration:

Header hydrate
ProductInfo hydrate
Comments hydrate
BuyButton hydrate
Footer hydrate

本质上:

为了一个按钮,整页都要重复执行一遍。

这很浪费。


2. mismatch 风险被放大

前面说过:

hydration 本质是重复计算

那只要重复计算范围越大:

  • 时间差异
  • 环境差异
  • 状态差异

都会扩大。

整页 hydration 意味着:

整页都有 mismatch 风险。


Islands 的思路:不要整页 hydration

Islands 架构把页面拆成:

  • Static HTML
  • Interactive Islands

例如:

<Header />
<ProductInfo />
<BuyButton client:load />
<Footer />

只有:

BuyButton

需要客户端接管。

其余部分:

  • 只保留 HTML
  • 永不 hydration

流程变成:

Server Render HTML
        ↓
静态部分直接展示
        ↓
仅局部组件 hydration

本质变化

传统 SSR:

HTML 先渲染,JS 再接管整页

Islands:

HTML 默认静态,只有少数区域需要 JS

所以它的核心思想不是:

“怎么更高效地 hydration”

而是:

尽量少 hydration,甚至不 hydration

这就是为什么说:

Islands 本质是在逃避 hydration。

不是因为 hydration 做得不好,而是因为:

hydration 天然昂贵且天然存在一致性问题。

既然如此,最好的办法不是优化它,而是减少它。


这样带来的收益

  1. JS 体积更小,只加载交互组件代码,不是整页 bundle。
  2. hydration 更快,因为只 hydration 局部。
  3. mismatch 风险更低,范围缩小:整页风险 → 局部风险
  4. 更接近“默认静态”,因为现代 Web 一个趋势是:Static by default, interactive when needed,也就是:
  • 默认静态
  • 局部增强

这和传统 SPA 思路完全相反。


一个更高的理解

SSR 第一阶段在解决:

首屏白屏问题

Hydration 第二阶段在解决:

HTML 如何变成交互页面

而 Islands 的想法是:

并不是所有 HTML 都需要变成交互页面。

所以它直接重新定义问题。

这就是架构升级。

不是:How to hydrate better
而是:How to hydrate less


八、最终结论

Hydration mismatch 不是一个“bug”,而是 SSR 架构的副作用。

因为 SSR 本质是让同一段渲染逻辑在两个不同环境执行,而只要存在时间、环境、状态或随机性的差异,就无法保证输出完全一致。

框架要求一致,是为了复用 DOM 提升性能;而不一致,就只能回退到重新渲染。

因此,hydration mismatch 并不是“可以彻底避免的问题”,而是一个需要被工程化控制的问题。

Traditional SSR 的问题不是不能工作,而是默认假设“整页都需要交互”。

但现实中,大部分页面内容本质是静态的。

Islands 架构通过把页面拆分为静态区域和交互区域,只对少量组件执行 hydration。

因此它并不是在优化 hydration,而是在架构层面减少 hydration 的发生范围。

某种意义上,Islands 并不是解决 hydration 的问题,而是在逃避 hydration 本身。



文章来源:https://www.cnblogs.com/zxlh1529/p/19950298
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!

标签:

相关文章

本站推荐

标签云