ReactJS - hydrateRoot() 方法



使用 React 构建网页时,我们需要处理服务器端生成的 HTML 内容。在这种情况下,hydrateRoot 函数非常有用。因此,我们将了解 hydrateRoot 是什么,如何使用它,以及它在某些情况下为什么很重要。

hydrateRoot 究竟是什么?

hydrateRoot 是一个 React 方法,允许我们在网页的 DOM 节点中显示 React 组件。这个 DOM 节点已经包含了 React 在服务器端生成的 HTML 内容。或者简单地说,它允许我们控制 React 已经创建的网页的一部分,并在客户端对其进行管理。

const root = hydrateRoot(domNode, reactNode, optionalObject)

简单来说,当我们在服务器端(而不是浏览器)渲染 React 应用时,它会为我们的组件生成 HTML。然后,hydrateRoot 函数在客户端使用,以附加事件监听器并使 HTML 具有交互性。

这个过程称为“水合”。它将服务器端渲染的 HTML 与客户端 JavaScript 相结合,以创建一个完全运行的应用程序。使用 hydrateRoot 有助于 React 优化渲染过程并增强用户体验。

参数

  • domNode − 为了放置我们的 React 组件,我们必须首先在网页中创建一个 DOM 元素。此 DOM 元素应该对应于服务器端渲染内容的根。

  • reactNode − 这是将在 DOM 节点内渲染的 React 组件。它通常是一个 JSX 元素,例如 <App />,它是在服务器端渲染的。

  • optionalObject − 我们可以提供一个包含附加参数的选项对象。这可以包含一个处理失败的回调函数。

hydrateRoot 方法返回一个包含两个方法的对象:render 和 unmount

render 方法用于更新已水合根内的 React 组件。

root.render(reactNode)

unmount 方法用于销毁 React 根内的已渲染树。

root.unmount()

如何使用它?

我们可以通过不同的方式使用 hydrateRoot。第一种是水化整个文档,第二种是处理不同的客户端和服务器内容,第三种是更新已水合的根组件。我们将逐一讨论这些方法。

示例

示例 − 水化整个文档

创建一个水化整个文档的 React 应用是一个有效的概念。它帮助我们使用 React 组件通过包含 HTML 结构来创建一个完整的网页。因此,我们将使用此概念创建一个应用 −

  • 使用“npx create-react-app”设置一个 React 应用。

  • 现在我们将为我们的应用创建一个组件。在 src 文件夹内,我们将为应用创建一个名为 App.js 的新组件。

  • 现在,我们将使用 hydrateRoot 函数在 HTML 文档中渲染我们的整个 React 应用。在项目文件夹中,我们有 src/index.js 文件,因此我们将用下面提到的新代码替换现有代码。

src/App.js

import React from 'react';

function App() {
   return (
      <html>
         <head>
            <meta charSet="utf-8" />
            <meta name="viewport" content="width=device-width, initial-scale=1" />
            <link rel="stylesheet" href="/styles.css" />
            <title>My React App</title>
         </head>
         <body>
            <div>
               <h1>Hello, World!</h1>
               <p>This is a simple React app.</p>
            </div>
         </body>
      </html>
   );
}

export default App;

src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { hydrateRoot } from 'react-dom/client';

const rootElement = document.getElementById('root');
if (rootElement) {
   hydrateRoot(document, <App />);
} else {
   ReactDOM.render(
      <React.StrictMode>
         <App />
      </React.StrictMode>,
      document.getElementById('root')
   );
}

输出

simple reactapp

此代码块检查 rootElement 是否存在。如果存在,它使用 hydrateRoot 将整个文档渲染为一个 React 应用。

示例 − 处理不同的客户端和服务器内容

创建一个简单的应用来演示处理不同客户端和服务器内容的这个概念。让我们看看下面的代码 −

  • 首先,我们需要设置一个 React 应用。

  • 现在,我们将创建一个组件,使用两遍渲染在服务器和客户端渲染不同的内容。在 src 文件夹内,我们将为应用创建一个名为 App.js 的组件。

  • 现在,我们将启动开发服务器以检查结果。

src/App.js

import React, { useState, useEffect } from 'react';

function App() {
   const [isClient, setIsClient] = useState(false);   
   useEffect(() => {
      setIsClient(true);
   }, []);   
   return (
   <div>
      <h1>
         {isClient ? 'Rendered on Client' : 'Rendered on Server'}
      </h1>
   </div>
   );
}

export default App;

输出

rendered on client

在上面的代码中,我们有一个状态变量 isClient,我们使用 useEffect hook 在客户端将其设置为 true。这让我们可以根据渲染发生在服务器还是客户端来呈现不同的内容。

示例 − 更新已水合的根组件

我们将创建一个小的 React 应用,显示一个计数器并每秒刷新一次以显示已水合的根组件。这个概念解释了如何使用 root.render 在组件水化后更新它。让我们看看代码 −

  • 首先创建一个新项目,并在终端或命令提示符中导航到我们的项目目录。

  • 现在我们将修改 src 文件夹中名为 App.js 的 App 组件。现在在这个文件中,我们将创建一个简单的计数器 App。在这个文件中,组件接受一个 counter prop。这个 prop 用于初始化计数器的值。因此,useEffect hook 每秒都会增加应用中的计数器。

  • 现在我们将修改 src/index.js 文件以使用 hydrateRoot 并每秒更新 App 组件 −

src/App.js

import React, { useState, useEffect } from 'react';

function App({ counter }) {
   const [count, setCount] = useState(counter);   
   useEffect(() => {
   const interval = setInterval(() => {
      setCount(count + 1);
   }, 1000);   
   return () => clearInterval(interval);
   }, [count]);   
   return (
   <div>
      <h1>The Counter: {count}</h1>
      <p>It is updating every second.</p>
   </div>
   );
}

export default App;

src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { hydrateRoot } from 'react-dom/client';

const rootElement = document.getElementById('root');

if (rootElement) {
   const root = hydrateRoot(rootElement, <App counter={0} />);   
   let i = 0;
   setInterval(() => {
      root.render(<App counter={i} />);
      i++;
   }, 1000);
} else {
   ReactDOM.render(
      <React.StrictMode>
         <App counter={0} />
      </React.StrictMode>,
      rootElement
   );
}

输出

the counter 6 updating

此代码使用 hydrateRoot 初始化根,然后连续调用 root.render 以每秒更新 App 组件,使其计数器值增加。

限制

  • 当我们使用 hydrateRoot 时,它期望我们之前在网页上显示的内容与服务器放置的内容相似。如果它们不匹配,则会出现问题。

  • 如果我们在 React 完成设置(这是水合)之前尝试更改网页上的任何内容,React 将删除所有内容并重新开始。

  • 我们使用 root.unmount 从 React 正在处理的网页中删除所有内容。

总结

React 的 hydrateRoot 方法是一种强大的机制,它允许我们在客户端更新和控制 React 内容,同时确保有效的性能。但是,当我们希望使用动态 React 组件增强服务器端渲染的 HTML 内容时,通常会使用 hydrateRoot。

reactjs_reference_api.htm
广告