什么是水合

所谓水合(Hydration),指的是 React 为预渲染的 HTML 添加事件处理程序,将其转为完全可交互的应用程序的过程。

React 提供了 hydrateRoot 客户端 API,通常搭配 react-dom/server 一起使用。先由 react-dom/server 生成 HTML,再调用 hydrateRoot 为生成的 HTML 进行水合,伪代码如下:

# 服务端
import { renderToString } from 'react-dom/server';
const html = renderToString(<App />);

# 客户端
import { hydrateRoot } from 'react-dom/client';
hydrateRoot(document.getElementById('root'), <App />);

与我们使用 React 时常用的 createRoot 不同,creatRoot 会重新创建 DOM 节点,而 hydrateRoot 会尽可能复用已有的 DOM 节点。

那具体是怎么进行水合的呢?

这就要说到 React 的渲染原理了。你可以这样简单粗暴的理解:

当调用 hydateRoot 的时候,会传入组件(例子中的 ),React 会据此构建 React 组件树,并按照 组件树的顺序遍历真实的 DOM 树,判断 DOM 树和组件树是否对应,如何对应,则跳过创建 DOM 节点的环节,复用当前 DOM 节点,添加事件并进行关联。

所以水合的前提是 DOM 树和组件树渲染一致。

常见的水合错误

  1. HTML 元素错误嵌套

  1. 渲染时使用 typeof window !== 'undefined' 等判断

  1. 渲染时使用客户端 API 如 window、localStorage 等

  1. 使用时间相关的 API,如 Date.now()

解决方法

  1. 是使用 useEffect 来处理:

  1. 禁用特定组件的 SSR 渲染

为什么会渲染不一致呢?本质上还是客户端组件既在服务端也在客户端渲染一份,干脆取消掉客户端组件的服务端渲染,为此需要借助 Next.js 提供的 dynamic 函数。

  1. 使用 suppressHydrationWarning 取消错误提示

  1. 自定义 hook

最后更新于

这有帮助吗?