Skip to content

Commit

Permalink
translate hydrate into “激活” (#1583)
Browse files Browse the repository at this point in the history
  • Loading branch information
awxiaoxian2020 committed Sep 4, 2024
1 parent acce298 commit 5b5bbe4
Show file tree
Hide file tree
Showing 15 changed files with 52 additions and 52 deletions.
4 changes: 2 additions & 2 deletions src/content/blog/2022/03/08/react-18-upgrade-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ root.render(<AppWithCallbackAfterRender />);

</Note>

最后如果应用通过 hydrate 使用了服务端渲染,你需要将 `hydrate` 升级到 `hydrateRoot`
最后如果应用通过激活使用了服务端渲染,你需要将 `hydrate` 升级到 `hydrateRoot`

```js
// 之前
Expand Down Expand Up @@ -306,7 +306,7 @@ globalThis.IS_REACT_ACT_ENVIRONMENT = true;
## 其他破坏性变更 {/*other-breaking-changes*/}

* **一致的 useEffect 时间**:现在,如果更新是在类似点击或者敲击键盘事件这样的离散用户输入事件期间触发,React 总是同步刷新 Effect 函数。而之前的行为不是一直可预测或者一致的。
* **更严格的 hydrate 报错**由于缺失或者额外的文本而导致的 hydrate 不匹配现在会作为错误而不是告警对待。React 将不再试图通过在客户端增加或删除节点来“修补”单个节点来匹配服务端标记,并且将会回退客户端渲染到树中最近的 `<Suspense>` 边界。这可以保证 hydrate 树保持一致并且避免可能由 hydrate 不匹配导致的隐私和安全漏洞
* **更严格的激活报错**由于缺失或者额外的文本而导致的激活内容不匹配现在会作为错误而不是告警对待。React 将不再试图通过在客户端增加或删除节点来“修补”单个节点来匹配服务端标记,并且将会回退客户端渲染到树中最近的 `<Suspense>` 边界。这可以保证激活树保持一致并且避免可能由激活内容不匹配导致的隐私和安全漏洞
* **Suspense 树一直保持一致**:如果一个组件在它完全被添加到树上之前挂起,React 将不会把它以不完整的状态添加到树或者触发它的 effect。React 会完全扔掉新树,等待异步操作结束,然后重新尝试从头开始再次渲染。React 会同时渲染重试尝试,并且不会阻塞浏览器。
* **使用 Suspense 的 Layout Effect**:当一个树重新挂起并恢复为后备方案时,现在的 React 会清理 layout effect,然后在边界内的内容再次显示时重新创建它们。这修复了一个在与 Suspense 一起使用时的问题:阻止组件库正确测量布局。
* **新的 JavaScript 环境要求**:React 现在依赖于现代浏览器特性,包括 `Promise``Symbol``Object.assign`。如果你需要支持像 Internet Explorer 这样较老版本的浏览器和设备,它们本身不提供现代浏览器特性或者有不兼容的实现,可以考虑在打包后的应用中包含全局的 polyfill。
Expand Down
8 changes: 4 additions & 4 deletions src/content/blog/2022/03/29/react-v18.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ React 18 中的 Suspense 在与 Transition API 结合时效果最好。如果你
* `createRoot`:为 `render` 或者 `unmount` 创建根节点的新方法。请用它替代 `ReactDOM.render`。如果没有它,React 18 中的新功能就无法生效。
* `hydrateRoot`:hydrate 服务端渲染的应用的新方法。使用它来替代 `ReactDOM.hydrate` 与新的 React DOM 服务端 API 一起使用。如果没有它,React 18 中的新功能就无法生效。

`createRoot``hydrateRoot` 都能接受一个新的可选参数叫做 `onRecoverableError`,它能在 React 在渲染或者 hydrate 过程发生错误后又恢复时,做日志记录对你进行通知。默认情况下,React 会使用 [`reportError`](https://developer.mozilla.org/en-US/docs/Web/API/reportError),如果在老旧版本浏览器中,则会使用 `console.error`
`createRoot``hydrateRoot` 都能接受一个新的可选参数叫做 `onRecoverableError`,它能在 React 在渲染或者激活过程发生错误后又恢复时,做日志记录对你进行通知。默认情况下,React 会使用 [`reportError`](https://developer.mozilla.org/en-US/docs/Web/API/reportError),如果在老旧版本浏览器中,则会使用 `console.error`


[参阅 React DOM Client 的文档](/reference/react-dom/client)
Expand Down Expand Up @@ -232,7 +232,7 @@ React 18 中的 Suspense 在与 Transition API 结合时效果最好。如果你

#### useId {/*useid*/}

`useId` 是一个新的Hook,用于生成在客户端和服务端两侧都独一无二的 id,避免 hydrate 后两侧内容不匹配。它主要用于需要唯一 id 的,具有集成 API 的组件库。这个更新不仅解决了一个在 React 17 及更低版本中的存在的问题,而且它会在 React 18 中发挥更重要的作用,因为新的流式服务端渲染响应 HTML 的方式将是无序的,需要独一无二的 id 作为索引。[参阅文档](/reference/react/useId)
`useId` 是一个新的Hook,用于生成在客户端和服务端两侧都独一无二的 id,避免激活后两侧内容不匹配。它主要用于需要唯一 id 的,具有集成 API 的组件库。这个更新不仅解决了一个在 React 17 及更低版本中的存在的问题,而且它会在 React 18 中发挥更重要的作用,因为新的流式服务端渲染响应 HTML 的方式将是无序的,需要独一无二的 id 作为索引。[参阅文档](/reference/react/useId)

> Note
>
Expand Down Expand Up @@ -299,12 +299,12 @@ React 18 中的 Suspense 在与 Transition API 结合时效果最好。如果你
* 修复生成的 License 头。([#23004](https://github.com/facebook/react/pull/23004) [@vitaliemiron](https://github.com/vitaliemiron))
* 添加 `package.json` 作为入口点之一。 ([#22954](https://github.com/facebook/react/pull/22954) [@Jack](https://github.com/Jack-Works))
* 允许在 Suspense 边界外挂起。([#23267](https://github.com/facebook/react/pull/23267) [@acdlite](https://github.com/acdlite))
* 每当 hydrate 失败时记录一个可恢复的错误。([#23319](https://github.com/facebook/react/pull/23319) [@acdlite](https://github.com/acdlite))
* 每当激活失败时记录一个可恢复的错误。([#23319](https://github.com/facebook/react/pull/23319) [@acdlite](https://github.com/acdlite))

### React DOM {/*react-dom*/}

* 添加 `createRoot` 和 `hydrateRoot`。([#10239](https://github.com/facebook/react/pull/10239),[#11225](https://github.com/facebook/react/pull/11225),[#12117](https://github.com/facebook/react/pull/12117),[#13732](https://github.com/facebook/react/pull/13732),[#15502](https://github.com/facebook/react/pull/15502),[#15532](https://github.com/facebook/react/pull/15532),[#17035](https://github.com/facebook/react/pull/17035),[#17165](https://github.com/facebook/react/pull/17165),[#20669](https://github.com/facebook/react/pull/20669),[#20748](https://github.com/facebook/react/pull/20748),[#20888](https://github.com/facebook/react/pull/20888),[#21072](https://github.com/facebook/react/pull/21072),[#21417](https://github.com/facebook/react/pull/21417),[#21652](https://github.com/facebook/react/pull/21652),[#21687](https://github.com/facebook/react/pull/21687),[#23207](https://github.com/facebook/react/pull/23207),[#23385](https://github.com/facebook/react/pull/23385) [@acdlite](https://github.com/acdlite),[@bvaughn](https://github.com/bvaughn),[@gaearon](https://github.com/gaearon),[@lunaruan](https://github.com/lunaruan),[@rickhanlonii](https://github.com/rickhanlonii),[@trueadm](https://github.com/trueadm),and [@sebmarkbage](https://github.com/sebmarkbage))
* 添加选择性 hydrate。([#14717](https://github.com/facebook/react/pull/14717)[#14884](https://github.com/facebook/react/pull/14884)[#16725](https://github.com/facebook/react/pull/16725)[#16880](https://github.com/facebook/react/pull/16880)[#17004](https://github.com/facebook/react/pull/17004)[#22416](https://github.com/facebook/react/pull/22416)[#22629](https://github.com/facebook/react/pull/22629)[#22448](https://github.com/facebook/react/pull/22448)[#22856](https://github.com/facebook/react/pull/22856)[#23176](https://github.com/facebook/react/pull/23176) [@acdlite](https://github.com/acdlite)[@gaearon](https://github.com/gaearon)[@salazarm](https://github.com/salazarm),and [@sebmarkbage](https://github.com/sebmarkbage))
* 添加选择性激活。([#14717](https://github.com/facebook/react/pull/14717)[#14884](https://github.com/facebook/react/pull/14884)[#16725](https://github.com/facebook/react/pull/16725)[#16880](https://github.com/facebook/react/pull/16880)[#17004](https://github.com/facebook/react/pull/17004)[#22416](https://github.com/facebook/react/pull/22416)[#22629](https://github.com/facebook/react/pull/22629)[#22448](https://github.com/facebook/react/pull/22448)[#22856](https://github.com/facebook/react/pull/22856)[#23176](https://github.com/facebook/react/pull/23176) [@acdlite](https://github.com/acdlite)[@gaearon](https://github.com/gaearon)[@salazarm](https://github.com/salazarm),and [@sebmarkbage](https://github.com/sebmarkbage))
* 在已知的 ARIA 属性列表中增加 `aria-description`。([#22142](https://github.com/facebook/react/pull/22142) [@mahyareb](https://github.com/mahyareb))
* 为 video 元素添加 `onResize` 事件。([#21973](https://github.com/facebook/react/pull/21973) [@rileyjshaw](https://github.com/rileyjshaw))
*`imageSizes``imageSrcSet` 添加到已知属性中。([#22550](https://github.com/facebook/react/pull/22550) [@eps1lon](https://github.com/eps1lon))
Expand Down
8 changes: 4 additions & 4 deletions src/content/blog/2024/04/25/react-19.md
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,7 @@ function MyInput({placeholder, ref}) {

</Note>

### hydration 错误的差异 {/*diffs-for-hydration-errors*/}
### 激活错误的差异 {/*diffs-for-hydration-errors*/}

`react-dom` 中,我们也改进了水合错误的错误报告。例如,现在不再在 DEV 中记录多个没有任何不匹配信息的错误:

Expand Down Expand Up @@ -682,11 +682,11 @@ function MyComponent() {

### 兼容第三方脚本和扩展 {/*compatibility-with-third-party-scripts-and-extensions*/}

我们改进了 hydration,以考虑第三方脚本和浏览器扩展。
我们改进了激活机制,以考虑第三方脚本和浏览器扩展。

在 hydration 过程中,如果在客户端渲染的元素与从服务器获取的 HTML 中找到的元素不匹配,React 将强制进行客户端重新渲染以修复内容。以前,如果一个元素是由第三方脚本或浏览器扩展插入的,它会触发一个不匹配的错误并进行客户端渲染。
在激活过程中,如果在客户端渲染的元素与从服务器获取的 HTML 中找到的元素不匹配,React 将强制进行客户端重新渲染以修复内容。以前,如果一个元素是由第三方脚本或浏览器扩展插入的,它会触发一个不匹配的错误并进行客户端渲染。

在 React 19 中,`<head>``<body>` 中的意外标签将被跳过,避免了不匹配的错误。如果 React 需要由于无关的 hydration 不匹配而重新渲染整个文档,它将保留由第三方脚本和浏览器扩展插入的样式表。
在 React 19 中,`<head>``<body>` 中的意外标签将被跳过,避免了不匹配的错误。如果 React 需要由于无关的激活不匹配而重新渲染整个文档,它将保留由第三方脚本和浏览器扩展插入的样式表。

### 更好的错误报告 {/*error-handling*/}

Expand Down
38 changes: 19 additions & 19 deletions src/content/reference/react-dom/client/hydrateRoot.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,21 +56,21 @@ React 将会连接到内部有 `domNode` 的 HTML 上,然后接管其中的 `d
#### 警告 {/*caveats*/}
* `hydrateRoot()` 期望渲染内容与服务端渲染的内容完全相同。你应该将不匹配视为错误并进行修复。
* 在开发模式下,React 会在 hydrate 期间发出不匹配警告。在不匹配的情况下,不能保证内容差异会被修补。出于性能原因,这很重要,因为在大多数应用程序中,不匹配很少见,因此验证所有标记将是昂贵而不可行的。
* 在开发模式下,React 会在激活期间发出不匹配警告。在不匹配的情况下,不能保证内容差异会被修补。出于性能原因,这很重要,因为在大多数应用程序中,不匹配很少见,因此验证所有标记将是昂贵而不可行的。
* 你的应用程序可能只有一个 `hydrateRoot()` 函数调用。如果你使用框架,则可能会为你完成此调用。
* 如果你的应用程序是客户端渲染,并且没有已渲染好的 HTML,则不支持使用 `hydrateRoot()`。请改用 [`createRoot()`](/reference/react-dom/client/createRoot)。
---
### `root.render(reactNode)` {/*root-render*/}
使用 `root.render` 更新一个 hydrate 根组件中的 React 组件来渲染浏览器端 DOM 元素。
使用 `root.render` 更新一个激活根组件中的 React 组件来渲染浏览器端 DOM 元素。
```js
root.render(<App />);
```
React 将会在 hydrate `root` 中更新 `<App />`
React 将会在激活 `root` 中更新 `<App />`
[参见下面更多示例](#usage)。
Expand All @@ -85,7 +85,7 @@ React 将会在 hydrate `root` 中更新 `<App />`。
#### 警告 {/*root-render-caveats*/}
* 如果你在根节点还没有完成 hydrate 的情况下调用了 `root.render`,React 将清除现有的服务端渲染 HTML 内容,并将整个根节点切换到客户端渲染。
* 如果你在根节点还没有完成激活的情况下调用了 `root.render`,React 将清除现有的服务端渲染 HTML 内容,并将整个根节点切换到客户端渲染。
---
Expand Down Expand Up @@ -123,7 +123,7 @@ root.unmount();
## 用法 {/*usage*/}
### hydrate 服务端渲染的 HTML {/*hydrating-server-rendered-html*/}
### 激活服务端渲染的 HTML {/*hydrating-server-rendered-html*/}
如果你的应用程序的 HTML 是由 [`react-dom/server`](/reference/react-dom/client/createRoot) 生成的,你需要在客户端上进行 **hydrate**。
Expand All @@ -133,9 +133,9 @@ import { hydrateRoot } from 'react-dom/client';
hydrateRoot(document.getElementById('root'), <App />);
```
对于你的应用程序来说,这将 hydrate 你的服务端 HTML 来复苏里面的 <CodeStep step={1}>浏览器 DOM 节点</CodeStep>和 <CodeStep step={2}>React 组件</CodeStep>。通常,你只需要在启动时执行一次。如果你使用框架,则可能会自动在幕后执行此操作。
对于你的应用程序来说,这将激活你的服务端 HTML 来复苏里面的 <CodeStep step={1}>浏览器 DOM 节点</CodeStep>和 <CodeStep step={2}>React 组件</CodeStep>。通常,你只需要在启动时执行一次。如果你使用框架,则可能会自动在幕后执行此操作。
为了进行 hydrate,React 将把你的组件逻辑连接到服务器上生成的初始 HTML 中。hydrate 可以将来自服务器的初始 HTML 快照转换为在浏览器中运行的完全可交互应用。
为了进行激活,React 将把你的组件逻辑连接到服务器上生成的初始 HTML 中。激活可以将来自服务器的初始 HTML 快照转换为在浏览器中运行的完全可交互应用。
<Sandpack>
Expand Down Expand Up @@ -190,20 +190,20 @@ function Counter() {
这对于用户体验非常重要。用户会在你的 JavaScript 代码加载前花费一些时间来查看服务端生成的 HTML。服务端渲染通过显示应用输出的 HTML 快照来产生了应用程序加速加载的错觉。突然出现不同的内容会破坏这种错觉。这就是为什么服务端渲染输出必须与客户端初始渲染输出匹配。
导致 hydrate 错误的最常见原因包括
导致激活错误的最常见原因包括
* 根节点 React 生成的 HTML 周围存在额外的空白符(如换行符)。
* 在渲染逻辑中使用 `typeof window !== 'undefined'` 这样的判断。
* 在渲染逻辑中使用仅限于浏览器端的 API,例如 [`window.matchMedia`](https://developer.mozilla.org/zh-CN/docs/Web/API/Window/matchMedia)。
* 在服务器和客户端渲染不同的数据。
React 可以从一些 hydrate 错误中恢复,但 **你必须像处理其他 bug 一样修复它们**。在最好的情况下,它们会导致应用程序加载变慢;在最坏的情况下,事件处理程序可能会附加到错误的元素上。
React 可以从一些激活错误中恢复,但 **你必须像处理其他 bug 一样修复它们**。在最好的情况下,它们会导致应用程序加载变慢;在最坏的情况下,事件处理程序可能会附加到错误的元素上。
</Pitfall>
---
### hydrate 整个文档 {/*hydrating-an-entire-document*/}
### 激活整个文档 {/*hydrating-an-entire-document*/}
完全使用 React 构建的应用程序可以将整个文档作为 JSX 渲染,包括 [`<html>`](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/html) 标签:
Expand All @@ -225,7 +225,7 @@ function App() {
}
```
要对整个文档进行 hydrate 处理,将全局的 [`document`](https://developer.mozilla.org/zh-CN/docs/Web/API/Window/document) 作为 `hydrateRoot` 的第一个参数传递:
要对整个文档进行激活处理,将全局的 [`document`](https://developer.mozilla.org/zh-CN/docs/Web/API/Window/document) 作为 `hydrateRoot` 的第一个参数传递:
```js {4}
import { hydrateRoot } from 'react-dom/client';
Expand All @@ -236,11 +236,11 @@ hydrateRoot(document, <App />);
---
### 抑制不可避免的 hydrate 处理不匹配错误 {/*suppressing-unavoidable-hydration-mismatch-errors*/}
### 抑制不可避免的激活处理不匹配错误 {/*suppressing-unavoidable-hydration-mismatch-errors*/}
如果一个单独元素属性或文本内容在服务器和客户端之间是不可避免地不同的(例如,时间戳),则可以抑制 hydrate 处理不匹配警告
如果一个单独元素属性或文本内容在服务器和客户端之间是不可避免地不同的(例如,时间戳),则可以抑制激活处理不匹配警告
要消除对元素的 hydrate 处理警告,请添加 `suppressHydrationWarning={true}`
要消除对元素的激活处理警告,请添加 `suppressHydrationWarning={true}`
<Sandpack>
Expand Down Expand Up @@ -318,21 +318,21 @@ export default function App() {
</Sandpack>
这样,初始渲染将呈现与服务器相同的内容,避免不匹配,但是在 hydrate 之后会同步进行额外的渲染
这样,初始渲染将呈现与服务器相同的内容,避免不匹配,但是在激活之后会同步进行额外的渲染
<Pitfall>
这种方法使得 hydrate 变慢,因为你的组件需要渲染两次。要注意在网络连接较慢的情况下用户的体验。JavaScript 代码的加载时间可能会比初始的 HTML 渲染慢很多,因此在 hydrate 之后立即呈现不同的 UI 对用户来说可能也会感到不适。
这种方法使得激活变慢,因为你的组件需要渲染两次。要注意在网络连接较慢的情况下用户的体验。JavaScript 代码的加载时间可能会比初始的 HTML 渲染慢很多,因此在激活之后立即呈现不同的 UI 对用户来说可能也会感到不适。
</Pitfall>
---
### 更新 hydrate 根组件 {/*updating-a-hydrated-root-component*/}
### 更新激活根组件 {/*updating-a-hydrated-root-component*/}
在根组件 hydrate 完成之后,你可以调用 [`root.render`](#root-render) 来更新根 React 组件。**与 [`createRoot`](/reference/react-dom/client/createRoot) 不同的是,通常你不需要这样做,因为初始内容已经渲染为 HTML**。
在根组件激活完成之后,你可以调用 [`root.render`](#root-render) 来更新根 React 组件。**与 [`createRoot`](/reference/react-dom/client/createRoot) 不同的是,通常你不需要这样做,因为初始内容已经渲染为 HTML**。
如果在 hydrate 之后某个时刻调用了 `root.render`,并且组件树结构与之前渲染的相匹配,那么 React 将 [保留重置 state](/learn/preserving-and-resetting-state)。请注意,你可以在输入框中输入文字,这意味着在此示例中每秒钟重复调用的 `render` 不会破坏已有的组件状态:
如果在激活之后某个时刻调用了 `root.render`,并且组件树结构与之前渲染的相匹配,那么 React 将 [保留重置 state](/learn/preserving-and-resetting-state)。请注意,你可以在输入框中输入文字,这意味着在此示例中每秒钟重复调用的 `render` 不会破坏已有的组件状态:
<Sandpack>
Expand Down
Loading

0 comments on commit 5b5bbe4

Please sign in to comment.