react-selective-hydration
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSelective Hydration
选择性Hydration
In previous articles, we covered how SSR with hydration can improve user experience. React is able to (quickly) generate a tree on the server using the method that the library provides, which gets sent to the client after the entire tree has been generated. The rendered HTML is non interactive, until the JavaScript bundle has been fetched and loaded, after which React walks down the tree to hydrate and attaches the handlers.
renderToStringreact-dom/serverHowever, this approach can lead to some performance issues due to some limitations with the current implementation.
在之前的文章中,我们介绍了带hydration的SSR如何提升用户体验。React能够借助库提供的方法,在服务端快速生成一棵DOM树,整棵树生成完成后再发送给客户端。渲染出的HTML是无交互性的,直到JavaScript bundle被获取并加载完成,React才会遍历树进行hydration并绑定事件处理程序。
react-dom/serverrenderToString然而,当前实现的一些局限性会导致这种方法存在部分性能问题。
When to Use
适用场景
- Use this when you want to make parts of your SSR page interactive before all JavaScript has loaded
- This is helpful when slow components (e.g., data-fetching components) are blocking the entire page's hydration
- 当你希望在所有JavaScript加载完成前,让SSR页面的部分区域具备交互性时使用
- 当加载缓慢的组件(例如数据获取组件)阻塞了整个页面的hydration时,这种方法会很有帮助
Instructions
操作步骤
- Use boundaries to delineate independently hydratable chunks of UI
Suspense - Use (Node) or
renderToPipeableStream(edge) for streaming SSRrenderToReadableStream - Place heavy data-fetching components inside so they don't delay sibling hydration
Suspense - Ensure critical interactive components are not inside long-lived loading fallbacks
- Use (React 18+) to benefit from selective hydration
hydrateRoot
- 使用边界划分可独立hydrate的UI区块
Suspense - 使用(Node环境)或
renderToPipeableStream(边缘环境)进行流式SSRrenderToReadableStream - 将数据获取繁重的组件放在内部,避免延迟兄弟组件的hydration
Suspense - 确保关键交互组件不在长期存在的加载回退组件内部
- 使用(React 18+)以充分利用选择性hydration的优势
hydrateRoot
Details
详细说明
Before the server-rendered HTML tree is able to get sent to the client, all components need to be ready. This means that components that may rely on an external API call or any process that could cause some delays, might end up blocking smaller components from being rendered quickly.
Besides a slower tree generation, another issue is the fact that React only hydrates the tree once. This means that before React is able to hydrate any of the components, it needs to have fetched the JavaScript for all of the components before it's able to hydrate any of them. This means that smaller components (with smaller bundles) have to wait for the larger components's code to be fetched and loaded, until React is able to hydrate anything on your website. During this time, the website remained non-interactive.
React 18 solves these problems by allowing us to combine streaming server-side rendering with a new approach to hydration: Selective Hydration!
Instead of using , modern React SSR uses on Node runtimes or on Web Stream runtimes.
renderToStringrenderToPipeableStream()renderToReadableStream()These APIs, in combination with and , make it possible to start streaming HTML without having to wait for the larger components to be ready. This means that we can lazy-load components when using SSR without blocking the hydration of the rest of the page.
hydrateRoot()SuspenseThe component, which earlier slowed down the tree generation and TTI, is now wrapped in . This tells React to not let this component slow down the rest of the tree generation. Instead, React inserts the fallback components as the initially rendered HTML, and continues to generate the rest of the tree before it's sent to the client.
CommentsSuspenseIn the meantime, we're still fetching the external data that we need for the component.
CommentsSelective hydration makes it possible to already hydrate the components that were sent to the client, even before the component has been sent!
CommentsOnce the data for the component is ready, React starts streaming the HTML for this component, as well as a small to replace the fallback loader.
Comments<script>React starts the hydration after the new HTML has been injected.
React 18 fixes some issues that people often encountered when using SSR with React.
Streaming rendering allows you to start streaming components as soon as they're ready, without risking a slower FCP and TTI due to components that might take longer to generate on the server.
Components can be hydrated as soon as they're streamed to the client, since we no longer have to wait for all JavaScript to load to start hydrating and can start interacting with the app before all components have been hydrated.
Note (React 18+): Best Practices for Selective HydrationUse Suspense boundaries in your SSR code to delineate independent chunks of UI—each Suspense boundary can hydrate independently. Structure your code so that any heavy data-fetching component is inside a Suspense, so it doesn't delay the initial HTML or hydration of siblings. Next.js automatically wraps each route segment in a Suspense boundary for you (via).loading.jsIf writing your own SSR, use(orrenderToPipeableStream()) instead of the olderrenderToReadableStream, and provide anrenderToNodeStreamcallback to flush early HTML. React will attach event listeners progressively as chunks come in.onShellReadyEnsure critical interactive components are not inside a loading fallback when they appear on screen, or if they are, that the fallback is very short-lived. If a user sees a button, it should be hydratable immediately. Verify you're not using legacy APIs—usecorrectly for React 18+ to benefit from these performance boosts.hydrateRoot
在服务端渲染的HTML树能够发送给客户端之前,所有组件都需要准备就绪。这意味着那些依赖外部API调用或任何可能导致延迟的流程的组件,可能会阻碍小型组件快速渲染。
除了树生成速度较慢之外,另一个问题是React只会对树进行一次hydration。这意味着在React能够对任何组件进行hydration之前,它需要先获取所有组件的JavaScript代码。这就意味着小型组件(对应更小的bundle)必须等待大型组件的代码被获取并加载完成,React才能对网站上的任何内容进行hydration。在此期间,网站始终处于无交互状态。
React 18通过允许我们将流式服务端渲染与一种新的hydration方法——选择性Hydration相结合,解决了这些问题!
现代React SSR不再使用,而是在Node运行时使用,在Web Stream运行时使用。
renderToStringrenderToPipeableStream()renderToReadableStream()这些API与和结合使用,使得无需等待大型组件准备就绪即可开始流式传输HTML。这意味着我们在使用SSR时可以懒加载组件,而不会阻塞页面其余部分的hydration。
hydrateRoot()Suspense之前拖慢树生成速度和TTI的组件,现在被包裹在中。这会告知React不要让该组件拖慢其余树的生成速度。相反,React会将回退组件作为初始渲染的HTML插入,并在发送给客户端之前继续生成树的其余部分。
CommentsSuspense与此同时,我们仍在获取组件所需的外部数据。
Comments选择性Hydration使得即使在组件被发送之前,我们就可以对已发送到客户端的组件进行hydration!
Comments一旦组件的数据准备就绪,React就会开始流式传输该组件的HTML,以及一段用于替换回退加载器的小型脚本。
Comments<script>新HTML注入完成后,React开始进行hydration。
React 18修复了人们在使用React SSR时经常遇到的一些问题。
流式渲染允许你在组件准备就绪后立即开始流式传输,不会因服务端生成耗时较长的组件而导致FCP和TTI变慢。
组件一被流式传输到客户端就可以进行hydration,因为我们不再需要等待所有JavaScript加载完成才能开始hydration,并且可以在所有组件完成hydration之前就与应用进行交互。
注意(React 18+):选择性Hydration最佳实践在你的SSR代码中使用Suspense边界划分独立的UI区块——每个Suspense边界都可以独立进行hydration。构建代码时,将任何数据获取繁重的组件放在Suspense内部,避免延迟初始HTML的生成或兄弟组件的hydration。Next.js会自动通过为每个路由段包裹一个Suspense边界。loading.js如果自行编写SSR代码,请使用(或renderToPipeableStream())替代旧版的renderToReadableStream,并提供renderToNodeStream回调以提前刷新HTML。React会随着区块的到来逐步附加事件监听器。onShellReady确保关键交互组件不在加载回退组件内部(当它们显示在屏幕上时),如果必须放在内部,也要确保回退组件的存在时间非常短。如果用户看到一个按钮,它应该能够立即被hydrate。确认你没有使用旧版API——正确使用React 18+的以获得这些性能提升。hydrateRoot