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')
	 	);
}

输出

简单的 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;

输出

在客户端上呈现

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

示例 − 更新水合根组件

我们将创建一个小型 React 应用程序,该应用程序显示一个计数器并每秒刷新一次以显示一个水合根组件。这个概念解释了如何使用 root.render 在组件被冻结后更新组件。让我们看看代码 -

  • 首先创建一个新项目,然后在终端或命令提示符中导航到我们的项目目录。
  • 现在我们将修改位于名为 App.js 的 src 文件夹中的 App 组件。现在在这个文件中,我们将创建一个简单的计数器 App。在此文件中,组件接受一个计数器属性。而这个道具是用来初始化计数器值的。因此,useEffect 钩子在应用中每秒增加计数器。
  • 现在我们将修改 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
	 	);
}

输出

计数器 6 更新

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

局限性

  • 当我们使用 hydrateRoot 时,它希望我们之前在网页上显示的内容与服务器放置在那里的内容相似。如果它们不匹配,这是一个问题。
  • 如果我们在 React 完成设置之前尝试更改网页上的任何内容(这是冻结),React 将删除所有内容并重新开始。
  • 我们使用 root.unmount 从 React 正在处理的网页中删除所有内容。

总结

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

打印页面