已弃用

此 API 将在未来 React 主要版本中移除。

在 React 18 中,hydrate 已被 hydrateRoot 替代。在 React 18 中使用 hydrate 会发出警告,提示您的应用程序的行为将与运行 React 17 时一样。了解更多信息,请访问 此处

hydrate 允许您在浏览器 DOM 节点中显示 React 组件,该节点的 HTML 内容之前由 React 17 及以下版本的 react-dom/server 生成。

hydrate(reactNode, domNode, callback?)

参考

hydrate(reactNode, domNode, callback?)

在 React 17 及以下版本中调用 hydrate,将 React“附加”到已由 React 在服务器环境中渲染的现有 HTML。

import { hydrate } from 'react-dom';

hydrate(reactNode, domNode);

React 将附加到 domNode 中存在的 HTML,并接管其中 DOM 的管理。完全使用 React 构建的应用程序通常只有一个 hydrate 调用及其根组件。

请参阅下面的更多示例。

参数

  • reactNode:用于渲染现有 HTML 的“React 节点”。这通常是像 <App /> 这样的 JSX 代码段,它在 React 17 中使用 ReactDOM Server 方法(如 renderToString(<App />))渲染。

  • domNode:在服务器上渲染为根元素的 DOM 元素

  • 可选callback:一个函数。如果传递,React 将在您的组件完成 hydration 后调用它。

返回值

hydrate 会返回 null。

注意事项

  • hydrate 希望渲染的内容与服务端渲染的内容完全相同。React 可以修补文本内容的差异,但你应该将不匹配视为错误并修复它们。
  • 在开发模式下,React 会在 hydration 过程中针对不匹配发出警告。但不保证属性差异会在不匹配的情况下得到修补。这对于性能来说很重要,因为在大多数应用程序中,不匹配的情况很少见,因此验证所有标记的成本过高。
  • 你的应用程序中很可能只有一个 hydrate 调用。如果你使用的是框架,它可能会为你进行此调用。
  • 如果你的应用程序是客户端渲染的,并且没有预先渲染的 HTML,则不支持使用 hydrate()。请改用 render() (适用于 React 17 及以下版本) 或 createRoot() (适用于 React 18+)。

用法

调用 hydrateReact 组件 附加到服务端渲染的 浏览器 DOM 节点 中。

import { hydrate } from 'react-dom';

hydrate(<App />, document.getElementById('root'));

不支持使用 hydrate() 来渲染纯客户端应用程序(没有服务端渲染 HTML 的应用程序)。请改用 render() (在 React 17 及以下版本中) 或 createRoot() (在 React 18+ 中)。

hydrate 服务端渲染的 HTML

在 React 中,“hydration” 是指 React 如何“附加”到已由 React 在服务端环境中渲染的现有 HTML。在 hydration 过程中,React 将尝试将事件监听器附加到现有的标记,并在客户端接管应用程序的渲染。

在完全使用 React 构建的应用程序中,通常只会在启动时 hydrate 一个“根”组件,一次性完成整个应用程序的 hydrate

import './styles.css';
import { hydrate } from 'react-dom';
import App from './App.js';

hydrate(<App />, document.getElementById('root'));

通常情况下,你不应该再次调用 hydrate,也不应该在更多的地方调用它。从现在开始,React 将管理应用程序的 DOM。要更新 UI,你的组件将 使用状态。

有关 hydration 的更多信息,请参阅 hydrateRoot 的文档。


抑制不可避免的 hydration 不匹配错误

如果单个元素的属性或文本内容在服务端和客户端之间不可避免地不同(例如,时间戳),则可以抑制 hydration 不匹配警告。

要抑制元素上的 hydration 警告,请添加 suppressHydrationWarning={true}

export default function App() {
  return (
    <h1 suppressHydrationWarning={true}>
      Current Date: {new Date().toLocaleDateString()}
    </h1>
  );
}

这只在一级深度有效,并且是一个应急方案。不要过度使用它。除非是文本内容,否则 React 仍然不会尝试修补它,因此它可能会在以后的更新中保持不一致。


处理不同的客户端和服务端内容

如果你有意需要在服务端和客户端渲染不同的内容,则可以进行两次渲染。在客户端渲染不同内容的组件可以读取 状态变量,例如 isClient,你可以在 Effect 中将其设置为 true

import { useState, useEffect } from "react";

export default function App() {
  const [isClient, setIsClient] = useState(false);

  useEffect(() => {
    setIsClient(true);
  }, []);

  return (
    <h1>
      {isClient ? 'Is Client' : 'Is Server'}
    </h1>
  );
}

这样,第一次渲染将渲染与服务端相同的内容,避免不匹配,但在 hydration 之后会立即同步进行第二次渲染。

陷阱

这种方法会降低 hydration 的速度,因为你的组件必须渲染两次。请注意在网络连接缓慢的情况下的用户体验。JavaScript 代码的加载时间可能明显晚于初始 HTML 渲染,因此在 hydration 之后立即渲染不同的 UI 可能会让用户感到不适。