Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/content/blog/2024/10/21/react-compiler-beta-release.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ React 团队很高兴分享新的内容:

在 [React Conf 2024](/blog/2024/05/22/react-conf-2024-recap) 上,我们宣布了 React 编译器的实验版本,这是一个构建时工具,可通过自动记忆化来优化 React 应用程序。[你可以在这里找到对 React 编译器的介绍](/learn/react-compiler)。

自第一个版本以来,我们修复了 React 社区报告的许多错误, 收到了多个高质量的错误修复和对编译器的贡献 [^1],使编译器能够更好地适应多种 JavaScript 模式,并继续在 Meta 上更广泛地推出编译器。
自第一个版本以来,我们修复了 React 社区报告的许多错误,收到了多个高质量的错误修复和对编译器的贡献 [^1],使编译器能够更好地适应多种 JavaScript 模式,并继续在 Meta 上更广泛地推出编译器。

在这篇文章中,我们想分享 React 编译器的下一步发展。

Expand Down
6 changes: 3 additions & 3 deletions src/content/blog/2024/12/05/react-19.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ __本文的日期已更新,以反映稳定版的发布日期。__

<Intro>

React 19 版本现在可以在 npm 上使用了!
React 19 版本现在可以在 npm 上使用了!

</Intro>

在我们的 [React 19 升级指南](/blog/2024/04/25/react-19-upgrade-guide) 中, 我们分享了将应用程序升级到 React 19 的分步说明。在这篇文章中,我们将概述 React 19 的新特性,以及如何使用它们。
在我们的 [React 19 升级指南](/blog/2024/04/25/react-19-upgrade-guide) 中,我们分享了将应用程序升级到 React 19 的分步说明。在这篇文章中,我们将概述 React 19 的新特性,以及如何使用它们。

- [React 19 中的新功能](#whats-new-in-react-19)
- [React 19 中的改进](#improvements-in-react-19)
Expand Down Expand Up @@ -360,7 +360,7 @@ React 19 包含了所有从 Canary 渠道引入的 React 服务器组件功能

<Note>

#### 如何构建对服务器组件的支持? {/*how-do-i-build-support-for-server-components*/}
#### 如何构建对服务器组件的支持? {/*how-do-i-build-support-for-server-components*/}

虽然 React 19 中的 React 服务器组件是稳定的,并且在主版本之间不会发生破坏,但用于实现 React 服务器组件打包器或框架的底层 API 不遵循 semver,并可能在 React 19.x 的小版本之间发生破坏。

Expand Down
2 changes: 1 addition & 1 deletion src/content/blog/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ In React Labs posts, we write about projects in active research and development.

<BlogCard title="React v19 " date="December 5, 2024" url="/blog/2024/12/05/react-19">

在我们的 React 19 升级指南中, 我们分享了将应用程序升级到 React 19 的分步说明。在这篇文章中,我们将概述 React 19 的新特性,以及如何使用它们……
在我们的 React 19 升级指南中,我们分享了将应用程序升级到 React 19 的分步说明。在这篇文章中,我们将概述 React 19 的新特性,以及如何使用它们……

</BlogCard>

Expand Down
6 changes: 3 additions & 3 deletions src/content/learn/build-a-react-app-from-scratch.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ React 生态系统中包含许多用于解决这些问题的工具。我们列

路由是现代应用程序的核心部分,通常与数据获取(包括为整个页面预取数据以加快加载速度)、代码拆分(以最小化客户端包的大小)和页面渲染方法(决定每个页面的生成方式)集成在一起。

我们建议使用:
我们建议使用:

- [React Router](https://reactrouter.com/start/data/custom)
- [Tanstack Router](https://tanstack.com/router/latest)
Expand Down Expand Up @@ -115,7 +115,7 @@ React 生态系统中包含许多用于解决这些问题的工具。我们列

通过路由拆分代码,并与打包和数据获取集成,可以减少应用程序的初始加载时间以及渲染应用程序最大可见内容所需的时间 ([最大内容绘制](https://web.dev/articles/lcp))。

有关代码拆分的说明,请参阅你的构建工具文档:
有关代码拆分的说明,请参阅你的构建工具文档:
- [Vite 构建优化](https://vite.dev/guide/features.html#build-optimizations)
- [Parcel 代码拆分](https://parceljs.org/features/code-splitting/)
- [Rsbuild 代码拆分](https://rsbuild.dev/guide/optimization/code-splitting)
Expand All @@ -140,4 +140,4 @@ React 生态系统中包含许多用于解决这些问题的工具。我们列

这些只是新应用在从头开始构建时需要考虑的功能的几个例子。你会遇到的许多限制可能很难解决,因为每个问题都与其他问题相互关联,并且可能需要你不熟悉的领域的深入专业知识。

如果你不想自己解决这些问题, 你可以 [从一个框架开始](/learn/creating-a-react-app),该框架开箱即用地提供这些功能。
如果你不想自己解决这些问题,你可以 [从一个框架开始](/learn/creating-a-react-app),该框架开箱即用地提供这些功能。
2 changes: 1 addition & 1 deletion src/content/learn/choosing-the-state-structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ body { margin: 0; padding: 0; height: 250px; }

<Pitfall>

如果你的 state 变量是一个对象时,请记住,[你不能只更新其中的一个字段](/learn/updating-objects-in-state) 而不显式复制其他字段。例如,在上面的例子中,你不能写成 `setPosition({ x: 100 })`,因为它根本就没有 `y` 属性! 相反,如果你想要仅设置 `x`,则可执行 `setPosition({ ...position, x: 100 })`,或将它们分成两个 state 变量,并执行 `setX(100)`。
如果你的 state 变量是一个对象时,请记住,[你不能只更新其中的一个字段](/learn/updating-objects-in-state) 而不显式复制其他字段。例如,在上面的例子中,你不能写成 `setPosition({ x: 100 })`,因为它根本就没有 `y` 属性!相反,如果你想要仅设置 `x`,则可执行 `setPosition({ ...position, x: 100 })`,或将它们分成两个 state 变量,并执行 `setX(100)`。

</Pitfall>

Expand Down
8 changes: 4 additions & 4 deletions src/content/learn/conditional-rendering.md
Original file line number Diff line number Diff line change
Expand Up @@ -446,8 +446,8 @@ export default function PackingList() {
* 在 React,你可以使用 JavaScript 来控制分支逻辑。
* 你可以使用 `if` 语句来选择性地返回 JSX 表达式。
* 你可以选择性地将一些 JSX 赋值给变量,然后用大括号将其嵌入到其他 JSX 中。
* 在 JSX 中,`{cond ? <A /> : <B />}` 表示 *“当 `cond` 为真值时, 渲染 `<A />`,否则 `<B />`”*。
* 在 JSX 中,`{cond && <A />}` 表示 *“当 `cond` 为真值时, 渲染 `<A />`,否则不进行渲染”*。
* 在 JSX 中,`{cond ? <A /> : <B />}` 表示 *“当 `cond` 为真值时,渲染 `<A />`,否则 `<B />`”*。
* 在 JSX 中,`{cond && <A />}` 表示 *“当 `cond` 为真值时,渲染 `<A />`,否则不进行渲染”*。
* 快捷的表达式很常见,但如果你更倾向于使用 `if`,你也可以不使用它们。

</Recap>
Expand Down Expand Up @@ -540,9 +540,9 @@ export default function PackingList() {

在这个例子里,每个 `Item` 接收一个名为 `importance` 的数字类型属性。使用 `&&` 运算符渲染 “_(重要性:X)_”,以斜体呈现,但仅作用于那些难度值为非零的物品。你的物品列表后最终应该如下:

* 宇航服 _(重要性: 9)_
* 宇航服 _(重要性:9)_
* 带金箔的头盔
* Tam 的照片 _(重要性: 6)_
* Tam 的照片 _(重要性:6)_

注意别忘了在这两个标签之间加上一个空格!

Expand Down
2 changes: 1 addition & 1 deletion src/content/learn/creating-a-react-app.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ Next.js 由 [Vercel](https://vercel.com/) 维护。你可以 [将 Next.js 应用

**[React Router](https://reactrouter.com/start/framework/installation) 是 React 最流行的路由库,可以与 Vite 结合创建一个全栈 React 框架**。它强调标准的 Web API 并提供了多个 [可部署的模板](https://github.com/remix-run/react-router-templates) 适用于各种 JavaScript 运行时和平台。

要创建一个新的 React Router 框架项目,请运行:
要创建一个新的 React Router 框架项目,请运行:

<TerminalBlock>
npx create-react-router@latest
Expand Down
4 changes: 2 additions & 2 deletions src/content/learn/editor-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,12 @@ React 社区中其他较为流行的文本编辑器包括:

#### 保存并自动格式化 {/*formatting-on-save*/}

理想情况下,你应该在每次保存时自动格式化代码。VS Code 就包含该配置!
理想情况下,你应该在每次保存时自动格式化代码。VS Code 就包含该配置!

1. 在 VS Code, 按快捷键 `Ctrl/Cmd + Shift + P`.
2. 输入 "settings"
3. 按回车键
4. 在搜索栏, 输入 "format on save"
4. 在搜索栏,输入 "format on save"
5. 确保勾选 "format on save" 选项!

> 如果你的 ESLint 预设包含格式化规则,它们可能会与 Prettier 发生冲突。我们建议使用[`eslint-config-prettier`](https://github.com/prettier/eslint-config-prettier) 禁用你 ESLint 预设中的所有格式化规则,这样 ESLint 就只用于捕捉逻辑错误。如果你想在合并 PR 前强制执行文件的格式化,请在你的 CI 中使用 [`prettier --check`](https://prettier.io/docs/en/cli.html#--check) 命令。
10 changes: 5 additions & 5 deletions src/content/learn/extracting-state-logic-into-a-reducer.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ Reducer 是处理状态的另一种方式。你可以通过三个步骤将 `useS
2. **编写** 一个 reducer 函数;
3. 在你的组件中 **使用** reducer。

### 第 1 步: 将设置状态的逻辑修改成 dispatch 的一个 action {/*step-1-move-from-setting-state-to-dispatching-actions*/}
### 第 1 步:将设置状态的逻辑修改成 dispatch 的一个 action {/*step-1-move-from-setting-state-to-dispatching-actions*/}

你的事件处理程序目前是通过设置状态来 **实现逻辑的**:

Expand Down Expand Up @@ -288,7 +288,7 @@ dispatch({

</Note>

### 第 2 步: 编写一个 reducer 函数 {/*step-2-write-a-reducer-function*/}
### 第 2 步:编写一个 reducer 函数 {/*step-2-write-a-reducer-function*/}

reducer 函数就是你放置状态逻辑的地方。它接受两个参数,分别为当前 state 和 action 对象,并且返回的是更新后的 state:

Expand Down Expand Up @@ -461,7 +461,7 @@ export default function tasksReducer(tasks, action) {

</DeepDive>

### 第 3 步: 在组件中使用 reducer {/*step-3-use-the-reducer-from-your-component*/}
### 第 3 步:在组件中使用 reducer {/*step-3-use-the-reducer-from-your-component*/}

最后,你需要将 `tasksReducer` 导入到组件中。记得先从 React 中导入 `useReducer` Hook:

Expand Down Expand Up @@ -874,7 +874,7 @@ Reducer 并非没有缺点!以下是比较它们的几种方法:

* **代码体积:** 通常,在使用 `useState` 时,一开始只需要编写少量代码。而 `useReducer` 必须提前编写 reducer 函数和需要调度的 actions。但是,当多个事件处理程序以相似的方式修改 state 时,`useReducer` 可以减少代码量。
* **可读性:** 当状态更新逻辑足够简单时,`useState` 的可读性还行。但是,一旦逻辑变得复杂起来,它们会使组件变得臃肿且难以阅读。在这种情况下,`useReducer` 允许你将状态更新逻辑与事件处理程序分离开来。
* **可调试性:** 当使用 `useState` 出现问题时, 你很难发现具体原因以及为什么。 而使用 `useReducer` 时, 你可以在 reducer 函数中通过打印日志的方式来观察每个状态的更新,以及为什么要更新(来自哪个 `action`)。 如果所有 `action` 都没问题,你就知道问题出在了 reducer 本身的逻辑中。 然而,与使用 `useState` 相比,你必须单步执行更多的代码。
* **可调试性:** 当使用 `useState` 出现问题时,你很难发现具体原因以及为什么。 而使用 `useReducer` 时, 你可以在 reducer 函数中通过打印日志的方式来观察每个状态的更新,以及为什么要更新(来自哪个 `action`)。 如果所有 `action` 都没问题,你就知道问题出在了 reducer 本身的逻辑中。 然而,与使用 `useState` 相比,你必须单步执行更多的代码。
* **可测试性:** reducer 是一个不依赖于组件的纯函数。这就意味着你可以单独对它进行测试。一般来说,我们最好是在真实环境中测试组件,但对于复杂的状态更新逻辑,针对特定的初始状态和 `action`,断言 reducer 返回的特定状态会很有帮助。
* **个人偏好:** 并不是所有人都喜欢用 reducer,没关系,这是个人偏好问题。你可以随时在 `useState` 和 `useReducer` 之间切换,它们能做的事情是一样的!

Expand Down Expand Up @@ -2081,7 +2081,7 @@ case 'edited_message': {
const message = state.messages[state.selectedId];
```

下面是完整答案:
下面是完整答案:

<Sandpack>

Expand Down
2 changes: 1 addition & 1 deletion src/content/learn/importing-and-exporting-components.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ img { margin: 0 10px 10px 0; height: 90px; }
2. **导出** 该文件中的函数组件(可以使用 [默认导出](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/export#using_the_default_export) 或 [具名导出](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/export#using_named_exports))
3. 在需要使用该组件的文件中 **导入**(可以根据相应的导出方式使用 [默认导入](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/import#importing_defaults) 或 [具名导入](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/import#import_a_single_export_from_a_module))。

这里将 `Profile` 组件和 `Gallery` 组件,从 `App.js` 文件中移动到了 `Gallery.js` 文件中。修改后,即可在 `App.js` 中导入 `Gallery.js` 中的 `Gallery` 组件:
这里将 `Profile` 组件和 `Gallery` 组件,从 `App.js` 文件中移动到了 `Gallery.js` 文件中。修改后,即可在 `App.js` 中导入 `Gallery.js` 中的 `Gallery` 组件:

<Sandpack>

Expand Down
4 changes: 2 additions & 2 deletions src/content/learn/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ const products = [
];
```

在你的组件中,使用 `map()` 函数将这个数组转换为 `<li>` 标签构成的列表:
在你的组件中,使用 `map()` 函数将这个数组转换为 `<li>` 标签构成的列表:

```js
const listItems = products.map(product =>
Expand Down Expand Up @@ -462,7 +462,7 @@ function MyButton() {

```

接着,将 `MyApp` 中的点击事件处理函数以及 **state 一同向下传递到** 每个 `MyButton` 中。你可以使用 JSX 的大括号向 `MyButton` 传递信息。就像之前向 `<img>` 等内置标签所做的那样:
接着,将 `MyApp` 中的点击事件处理函数以及 **state 一同向下传递到** 每个 `MyButton` 中。你可以使用 JSX 的大括号向 `MyButton` 传递信息。就像之前向 `<img>` 等内置标签所做的那样:

```js {11-12}
export default function MyApp() {
Expand Down
2 changes: 1 addition & 1 deletion src/content/learn/keeping-components-pure.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ export default function TeaGathering() {

<DeepDive>

#### React 为何侧重于纯函数? {/*why-does-react-care-about-purity*/}
#### React 为何侧重于纯函数? {/*why-does-react-care-about-purity*/}

编写纯函数需要遵循一些习惯和规程。但它开启了绝妙的机遇:

Expand Down
4 changes: 2 additions & 2 deletions src/content/learn/manipulating-the-dom-with-refs.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ const myRef = useRef(null);
myRef.current.scrollIntoView();
```

### 示例: 使文本输入框获得焦点 {/*example-focusing-a-text-input*/}
### 示例:使文本输入框获得焦点 {/*example-focusing-a-text-input*/}

在本例中,单击按钮将使输入框获得焦点:

Expand Down Expand Up @@ -84,7 +84,7 @@ export default function Form() {

虽然 DOM 操作是 ref 最常见的用例,但 `useRef` Hook 可用于存储 React 之外的其他内容,例如计时器 ID 。与 state 类似,ref 能在渲染之间保留。你甚至可以将 ref 视为设置它们时不会触发重新渲染的 state 变量!你可以在[使用 Ref 引用值](/learn/referencing-values-with-refs)中了解有关 ref 的更多信息。

### 示例: 滚动至一个元素 {/*example-scrolling-to-an-element*/}
### 示例:滚动至一个元素 {/*example-scrolling-to-an-element*/}

一个组件中可以有多个 ref。在这个例子中,有一个由三张图片和三个按钮组成的轮播,点击按钮会调用浏览器的 [`scrollIntoView()`](https://developer.mozilla.org/zh-CN/docs/Web/API/Element/scrollIntoView) 方法,在相应的 DOM 节点上将它们居中显示在视口中:

Expand Down
4 changes: 2 additions & 2 deletions src/content/learn/passing-data-deeply-with-context.md
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ export const LevelContext = createContext(1);

</Sandpack>

`createContext` 只需**默认值**这么一个参数。在这里, `1` 表示最大的标题级别,但是你可以传递任何类型的值(甚至可以传入一个对象)。你将在下一个步骤中见识到默认值的意义。
`createContext` 只需**默认值**这么一个参数。在这里,`1` 表示最大的标题级别,但是你可以传递任何类型的值(甚至可以传入一个对象)。你将在下一个步骤中见识到默认值的意义。

### Step 2:使用 Context {/*step-2-use-the-context*/}

Expand Down Expand Up @@ -869,7 +869,7 @@ Context 不局限于静态值。如果你在下一次渲染时传递不同的值
<Recap>

* Context 使组件向其下方的整个树提供信息。
* 传递 Context 的方法:
* 传递 Context 的方法:
1. 通过 `export const MyContext = createContext(defaultValue)` 创建并导出 context。
2. 在无论层级多深的任何子组件中,把 context 传递给 `useContext(MyContext)` Hook 来读取它。
3. 在父组件中把 children 包在 `<MyContext value={...}>` 中来提供 context。
Expand Down
2 changes: 1 addition & 1 deletion src/content/learn/preserving-and-resetting-state.md
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ label {

<Pitfall>

记住 **对 React 来说重要的是组件在 UI 树中的位置,而不是在 JSX 中的位置!** 这个组件在 `if` 内外有两个`return` 语句,它们带有不同的 `<Counter />` JSX 标签:
记住 **对 React 来说重要的是组件在 UI 树中的位置,而不是在 JSX 中的位置!** 这个组件在 `if` 内外有两个`return` 语句,它们带有不同的 `<Counter />` JSX 标签:

<Sandpack>

Expand Down
4 changes: 2 additions & 2 deletions src/content/learn/queueing-a-series-of-state-updates.md
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ function delay(ms) {

<Hint>

如果你没有思路,可以从下面的代码结构开始:
如果你没有思路,可以从下面的代码结构开始:

```js
export function getFinalState(baseState, queue) {
Expand Down Expand Up @@ -498,7 +498,7 @@ function TestCase({

<Solution>

这其实就是这一页中所描述的 React 用来计算最终 state 的算法:
这其实就是这一页中所描述的 React 用来计算最终 state 的算法:

<Sandpack>

Expand Down
2 changes: 1 addition & 1 deletion src/content/learn/react-compiler/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ export default defineConfig({
```
</Note>

或者, 你也可以通过 `@rolldown/plugin-babel` 直接使用 Babel 插件。
或者,你也可以通过 `@rolldown/plugin-babel` 直接使用 Babel 插件。

```js {3,9}
// vite.config.js
Expand Down
2 changes: 1 addition & 1 deletion src/content/learn/react-developer-tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ translators:
![React Developer Tools extension](/images/docs/react-devtools-extension.png)

### Safari 和其他浏览器 {/*safari-and-other-browsers*/}
为其他浏览器(比如,Safari),安装 [`react-devtools`](https://www.npmjs.com/package/react-devtools) npm 包:
为其他浏览器(比如,Safari),安装 [`react-devtools`](https://www.npmjs.com/package/react-devtools) npm 包:
```bash
# Yarn
yarn global add react-devtools
Expand Down
2 changes: 1 addition & 1 deletion src/content/learn/referencing-values-with-refs.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import { useRef } from 'react';
const ref = useRef(0);
```

`useRef` 返回一个这样的对象:
`useRef` 返回一个这样的对象:

```js
{
Expand Down
2 changes: 1 addition & 1 deletion src/content/learn/removing-effect-dependencies.md
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ button { margin: 10px; }

上面的计数器例子,本应该每秒递增,递增量可以通过两个按钮来控制。然而,由于你对 React “撒谎”,说这个 Effect 不依赖于任何东西,React 便一直使用初次渲染时的 `onTick` 函数。[在后续渲染中](/learn/state-as-a-snapshot#rendering-takes-a-snapshot-in-time), `count` 总是 `0` ,`increment` 总是 `1`。为什么?因为定时器每秒调用 `onTick` 函数,实际运行的是 `setCount(0 + 1)`<sup><a href="#note1">[1]</a></sup>,所以你总是看到 `1`。像这样的错误,当它们分散在多个组件中时,就更难解决了。

这里有一个比忽略 linter 更好的解决方案! 那便是将 `onTick` 添加到依赖中。(为了确保 interval 只设置一次,[使 `onTick` 成为 Effect Event](/learn/separating-events-from-effects#reading-latest-props-and-state-with-effect-events)。)
这里有一个比忽略 linter 更好的解决方案!那便是将 `onTick` 添加到依赖中。(为了确保 interval 只设置一次,[使 `onTick` 成为 Effect Event](/learn/separating-events-from-effects#reading-latest-props-and-state-with-effect-events)。)

**我们建议将依赖性 lint 错误作为一个编译错误来处理。如果你不抑制它,你将永远不会遇到像上面这样的错误**。本页面的剩下部分将介绍这个和其他情况的替代方案。

Expand Down
Loading
Loading