hydrate
hydrate
允许你在 React 17 及以下版本中将使用 react-dom/server
生成的 HTML 内容作为浏览器 DOM 节点,并在其中显示 React 组件。
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。这通常是像<App />
这样的 JSX 片段,并且在 React 17 中使用如renderToString(<App />)
的ReactDOM Server
方法进行渲染。 -
domNode
:在服务器中被渲染为根节点的 DOM 元素。 -
可选属性
callback
:一个函数。如果传递了该参数,React 将会在组件激活后调用它。
返回值
hydrate
返回 null
。
注意
hydrate
要求渲染的内容与服务器渲染的内容完全相同。尽管 React 可以修复文本内容的差异,但你应该首先将不匹配视为错误并进行修复。- 在开发模式下,React 会在激活期间警告不匹配的错误。如果存在不匹配情况,无法保证属性的差异会被修补。在大多数应用程序中不匹配是很少见的,所以验证所有标记的代价将会很高。因此考虑到性能原因,这是很重要的。
- 你的应用程序中可能只有一个
hydrate
调用。如果你使用了框架,它可能会为你执行此调用。 - 如果你的应用程序是客户端渲染的,并且没有已经渲染的 HTML,则不支持使用
hydrate()
。请改用 render()(适用于 React 17 及以下版本)或 createRoot()(适用于 React 18 及以上版本)。
用法
调用 hydrate
将 React 组件 附加(attach)到服务器渲染的 浏览器 DOM 节点。
import { hydrate } from 'react-dom';
hydrate(<App />, document.getElementById('root'));
不支持使用 hydrate()
渲染仅用于客户端的应用程序(没有服务器渲染的 HTML)。请改用 render()
(适用于 React 17 及以下版本)或 createRoot()
(适用于 React 18 及以上版本)。
激活服务器渲染的 HTML
在 React 中,激活(hydrate)是指将 React “附加(attach)”到在服务器环境中已由 React 渲染的现有 HTML 上。在激活期间,React 将尝试将事件监听器附加(attach)到现有标记,并在客户端上接管渲染应用程序。
在完全使用 React 构建的应用程序中,通常只会在第一次启动整个应用程序时,hydrate “根”节点。
import './styles.css'; import { hydrate } from 'react-dom'; import App from './App.js'; hydrate(<App />, document.getElementById('root'));
通常情况下,你不需要再次调用 hydrate
,也不需要在更多地方调用它。从此时开始,React 将会管理你的应用程序的 DOM。为了更新 UI,你的组件将会 使用 state。
有关激活的更多信息,请参阅 hydrateRoot
。
抑制不可避免的激活内容不匹配错误
如果服务器和客户端之间某个元素的属性或文本内容无法避免不同(比如一个时间戳),你可以禁止激活警告。
使用 suppressHydrationWarning={true}
禁止激活警告:
export default function App() { return ( <h1 suppressHydrationWarning={true}> 当前时间:{new Date().toLocaleDateString()} </h1> ); }
这只在同级深度上有效,而且是一种脱围机制,因此不要过度使用它。除非它是文本内容,否则 React 仍然不会尝试修补它,因此直至未来的更新它都可能会保持不一致。
处理不同的客户端和服务器内容
如果需要在服务器和客户端上故意渲染不同的内容,可以进行双重渲染。在客户端上渲染不同内容的组件可以读取像 isClient
这样的 state 变量,你可以在 effect 中将其设置为 true
:
import { useState, useEffect } from "react"; export default function App() { const [isClient, setIsClient] = useState(false); useEffect(() => { setIsClient(true); }, []); return ( <h1> {isClient ? '在客户端' : '在服务器'} </h1> ); }
这样,初始渲染过程将呈现与服务器相同的内容,并且避免不匹配的情况,但会在激活后立即同步并进行额外的渲染。