什么是水合

React 中的 Hydration(水合) 是服务器端渲染(SSR, Server-Side Rendering)的关键步骤,它让静态的 HTML 内容在客户端“活起来”,变为可交互的动态应用。以下是详细解释:


1. 什么是 Hydration?

  • 定义:Hydration 是 React 在客户端将 JavaScript 逻辑(事件处理、状态管理、交互逻辑等)“附加”到服务器预渲染的静态 HTML 上的过程。
  • 目的:复用服务器生成的 DOM 结构,避免完全重新渲染,从而提升性能和用户体验。

2. 为什么需要 Hydration?

  • 性能优化:用户首次访问页面时,服务器直接返回渲染好的 HTML(快速显示内容),随后客户端通过 Hydration 添加交互逻辑,减少白屏时间。
  • SEO 友好:搜索引擎可以直接抓取服务器生成的静态内容。
  • 保留初始状态:如果服务器渲染的 HTML 包含初始数据(如用户信息),Hydration 能保留这些状态,避免页面闪烁。

3. Hydration 的工作流程

  1. 服务器渲染:Node.js 使用 ReactDOMServer.renderToString() 或类似方法生成静态 HTML。
    1
    2
    3
    
    <div id="root">
      <button>点击次数:0</button>
    </div>
    
  2. 客户端加载:浏览器接收到 HTML 后立即展示静态内容,同时下载 JavaScript 代码。
  3. Hydration 阶段:客户端调用 ReactDOM.hydrateRoot()(React 18+)或旧版的 ReactDOM.hydrate(),将 React 组件与现有 DOM 关联。
    1
    2
    3
    
    // React 18+
    import { hydrateRoot } from "react-dom/client";
    hydrateRoot(document.getElementById("root"), <App />);
    
  4. 附加交互逻辑:React 对比服务器 HTML 和客户端组件树,复用 DOM 节点,绑定事件处理函数,恢复状态(如 useState 的初始值)。

4. Hydration 与普通渲染的区别

ReactDOM.render() / createRoot() ReactDOM.hydrate() / hydrateRoot()
完全重新创建 DOM 节点 复用现有 DOM 节点,仅附加逻辑
适用于纯客户端渲染(CSR) 专为 SSR + 客户端激活设计

5. 常见问题与注意事项

  • DOM 一致性:服务器和客户端渲染的组件必须生成相同的 DOM 结构,否则会导致控制台警告,甚至 Hydration 失败(客户端被迫重新渲染)。
  • 性能优化:避免在组件中依赖仅在客户端存在的对象(如 window),应在 useEffect 或生命周期钩子中处理。
  • 选择性 Hydration(React 18+):通过并发模式(Concurrent Mode),可以优先 Hydration 用户正在交互的部分,提升感知性能。

6. 示例代码

服务器端(Node.js)

1
2
3
import { renderToString } from "react-dom/server";
const html = renderToString(<App />);
// 发送 html 到客户端

客户端(React 18+):

1
2
3
4
import { hydrateRoot } from "react-dom/client";
import App from "./App";

const root = hydrateRoot(document.getElementById("root"), <App />);

为什么叫做水合

“Hydration”一词源自化学中的水合作用(物质与水结合的过程),在 React 中它被用作一种比喻,形象地描述了将静态内容转化为动态应用的过程。以下是具体解释:


1. 化学隐喻:从“干燥”到“湿润”

  • 静态 HTML 是“干燥”的:服务器渲染的 HTML 没有交互能力,如同干燥的土壤,内容完整但缺乏活力。
  • 客户端添加“水分”:通过 Hydration,React 将事件处理、状态管理等逻辑“注入”静态 HTML,就像给土壤浇水,使其变得“湿润”且充满生命力。

2. 编程中的通用术语

  • 前端框架的通用概念:类似概念在 Vue、Angular 中也被称为 “Hydration” 或 “Rehydration”,指代静态内容到动态应用的转换。
  • “脱水”(Dehydration)的对应:某些场景下,服务器会先“脱水”(提取初始状态),客户端再“水合”(恢复状态),形成一个完整的数据流动闭环。

3. React 中的设计哲学

  • 强调“激活”而非“重建”:React 选择“Hydrate”而非“Render”,是为了强调客户端不重新生成 DOM,而是直接复用现有结构并附加逻辑
  • 性能与体验的平衡:术语本身暗示了轻量级的操作(如水滴渗透),而非推倒重来,符合 SSR 优化首屏性能的目标。

4. 与“Rehydration”的区别

  • Rehydration:有时用于强调客户端“重新激活”状态(如从缓存恢复数据),但 React 官方文档统一使用 Hydration
  • React 18+ 的更新:尽管 API 从 hydrate() 变为 hydrateRoot(),核心术语仍保持一致。

5. 比喻的实际应用

假设服务器生成的 HTML 如下(无交互):

1
<button>点击次数:0</button>

Hydration 后,React 会绑定点击事件,并将按钮变为:

1
<button onclick="handleClick()">点击次数:0</button>

静态内容“活”了起来,就像干涸的土地被水滋润后焕发生机。