diff --git a/src/content/reference/react/useReducer.md b/src/content/reference/react/useReducer.md index 9107625375..0d9f963f21 100644 --- a/src/content/reference/react/useReducer.md +++ b/src/content/reference/react/useReducer.md @@ -20,7 +20,7 @@ const [state, dispatch] = useReducer(reducer, initialArg, init?) ### `useReducer(reducer, initialArg, init?)` {/*usereducer*/} -在组件的顶层作用域调用 `useReducer` 来创建一个用于管理状态的 [reducer](/learn/extracting-state-logic-into-a-reducer)。 +在组件的顶层作用域调用 `useReducer` 以创建一个用于管理状态的 [reducer](/learn/extracting-state-logic-into-a-reducer)。 ```js import { useReducer } from 'react'; @@ -34,12 +34,12 @@ function MyComponent() { // ... ``` -[参见下面的更多示例](#usage)。 +[参见下方更多示例](#usage)。 #### 参数 {/*parameters*/} -* `reducer`:用于更新 state 的纯函数。参数为 state 和 action ,返回值是更新后的 state。state 和 action 可以是任意合法值。 -* `initialArg`:用于初始化 state 的任意值。初始值的计算逻辑取决于下面的 `init` 参数。 +* `reducer`:用于更新 state 的纯函数。参数为 state 和 action,返回值是更新后的 state。state 与 action 可以是任意合法值。 +* `initialArg`:用于初始化 state 的任意值。初始值的计算逻辑取决于接下来的 `init` 参数。 * **可选参数** `init`:用于计算初始值的函数。如果存在,使用 `init(initialArg)` 的执行结果作为初始值,否则使用 `initialArg`。 #### 返回值 {/*returns*/} @@ -51,7 +51,7 @@ function MyComponent() { #### 注意事项 {/*caveats*/} -* `useReducer` 是一个 Hook,所以你只能在 **组件的顶层作用域** 或者自己的 Hook 中调用。不能在循环或条件语句中调用。如果你有这种需求,可以创建一个新的组件,并把 state 移入其中。 +* `useReducer` 是一个 Hook,所以只能在 **组件的顶层作用域** 或自定义 Hook 中调用,而不能在循环或条件语句中调用。如果你有这种需求,可以创建一个新的组件,并把 state 移入其中。 * 严格模式下 React 会 **调用两次 reducer 和初始化函数**,这可以 [帮助你发现意外的副作用](#my-reducer-or-initializer-function-runs-twice)。这只是开发模式下的行为,并不会影响生产环境。只要 reducer 和初始化函数是纯函数(理应如此)就不会改变你的逻辑。其中一个调用结果会被忽略。 --- @@ -68,7 +68,7 @@ function handleClick() { // ... ``` -React 会调用 `reducer` 函数来更新 state,`reducer` 函数的参数就是当前的 state 和你传给 `dispatch` 的 action。 +React 会调用 `reducer` 函数以更新 state,`reducer` 函数的参数为当前的 state 与传递的 action。 #### 参数 {/*dispatch-parameters*/} @@ -80,19 +80,19 @@ React 会调用 `reducer` 函数来更新 state,`reducer` 函数的参数就 #### 注意 {/*setstate-caveats*/} -* `dispatch` 函数 **是用来为下一次渲染更新 state 的**。因此在调用 `dispatch` 函数后读取 state [并不会拿到更新后的值](#ive-dispatched-an-action-but-logging-gives-me-the-old-state-value),也就是说只能获取到调用前的值。 +* `dispatch` 函数 **是为下一次渲染而更新 state**。因此在调用 `dispatch` 函数后读取 state [并不会拿到更新后的值](#ive-dispatched-an-action-but-logging-gives-me-the-old-state-value),也就是说只能获取到调用前的值。 -* 如果你提供的新值和当前的 `state` 相同(使用 [`Object.is`](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/is) 比较),React 会 **跳过组件和子组件的重新渲染**,这是一种优化手段。虽然在跳过重新渲染前 React 可能会调用你的组件,但是这不应该影响你的代码。 +* 如果你提供的新值与当前的 `state` 相同(使用 [`Object.is`](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/is) 比较),React 会 **跳过组件和子组件的重新渲染**,这是一种优化手段。虽然在跳过重新渲染前 React 可能会调用你的组件,但是这不应该影响你的代码。 -* React [会批量更新 state](/learn/queueing-a-series-of-state-updates)。state 会在 **所有事件函数执行完毕** 并且已经调用过它的 `set` 函数后进行更新,这可以防止在一个事件中多次进行重新渲染。如果在访问 DOM 等极少数情况下需要强制 react 提前更新,可以使用 [`flushSync`](/reference/react-dom/flushSync)。 +* React [会批量更新 state](/learn/queueing-a-series-of-state-updates)。state 会在 **所有事件函数执行完毕** 并且已经调用过它的 `set` 函数后进行更新,这可以防止在一个事件中多次进行重新渲染。如果在访问 DOM 等极少数情况下需要强制 React 提前更新,可以使用 [`flushSync`](/reference/react-dom/flushSync)。 --- -## 使用 {/*usage*/} +## 用法 {/*usage*/} ### 向组件添加 reducer {/*adding-a-reducer-to-a-component*/} -在组件的顶层作用域调用 `useReducer` 来创建一个用于管理状态的 [reducer](/learn/extracting-state-logic-into-a-reducer)。 +在组件的顶层作用域调用 `useReducer` 来创建一个用于管理状态(state)的 [reducer](/learn/extracting-state-logic-into-a-reducer)。 ```js [[1, 8, "state"], [2, 8, "dispatch"], [4, 8, "reducer"], [3, 8, "{ age: 42 }"]] import { useReducer } from 'react'; @@ -111,7 +111,7 @@ function MyComponent() { 1. 当前的 state,首次渲染时为你提供的 初始值。 2. `dispatch` 函数,让你可以根据交互修改 state。 -为了更新屏幕上的内容,使用一个表示用户操作的 *action* 来调用 `dispatch` 函数: +为了更新屏幕上的内容,使用一个表示用户操作的 action 来调用 `dispatch` 函数: ```js [[2, 2, "dispatch"]] function handleClick() { @@ -157,7 +157,7 @@ button { display: block; margin-top: 10px; } -`useReducer` 和 [`useState`](/reference/react/useState) 非常相似,但是它可以让你把状态更新逻辑从事件处理函数中移动到组件外部。详情可以参阅 [选择使用 `useState` 或 `useReducer`](/learn/extracting-state-logic-into-a-reducer#comparing-usestate-and-usereducer)。 +`useReducer` 和 [`useState`](/reference/react/useState) 非常相似,但是它可以让你把状态更新逻辑从事件处理函数中移动到组件外部。详情可以参阅 [对比 `useState` 和 `useReducer`](/learn/extracting-state-logic-into-a-reducer#comparing-usestate-and-usereducer)。 --- @@ -193,7 +193,7 @@ function reducer(state, action) { } ``` -action 可以是任意类型,不过通常实现为存在 `type` 属性的对象。也就是说它需要携带计算新的 state 值所必须的数据。 +action 可以是任意类型,不过通常至少是一个存在 `type` 属性的对象。也就是说它需要携带计算新的 state 值所必须的数据。 ```js {5,9-12} function Form() { @@ -212,9 +212,9 @@ function Form() { // ... ``` -action 的 type 依赖于组件的实际情况。[每个 action 都只描述一次交互,即使它会导致数据的多次更新](/learn/extracting-state-logic-into-a-reducer#writing-reducers-well)。state 的类型也是任意的,不过一般会使用对象或数组。 +action 的 type 依赖于组件的实际情况。[即使它会导致数据的多次更新,每个 action 都只描述一次交互](/learn/extracting-state-logic-into-a-reducer#writing-reducers-well)。state 的类型也是任意的,不过一般会使用对象或数组。 -阅读 [将状态逻辑提取到 reducer](/learn/extracting-state-logic-into-a-reducer) 来了解更多内容。 +阅读 [迁移状态逻辑至 Reducer 中](/learn/extracting-state-logic-into-a-reducer) 来了解更多内容。 @@ -509,7 +509,7 @@ ul, li { margin: 0; padding: 0; } -#### 使用 Immer 编写简介的更新逻辑 {/*writing-concise-update-logic-with-immer*/} +#### 使用 Immer 编写简洁的更新逻辑 {/*writing-concise-update-logic-with-immer*/} 如果使用复制方法更新数组和对象让你不厌其烦,那么可以使用 [Immer](https://github.com/immerjs/use-immer#useimmerreducer) 这样的库来减少一些重复的样板代码。Immer 让你可以专注于逻辑,因为它在内部均使用复制方法来完成更新: @@ -753,13 +753,13 @@ function TodoList({ username }) { 需要注意的是你传入的参数是 `createInitialState` 这个 **函数自身**,而不是执行 `createInitialState()` 后的返回值。这样传参就可以保证初始化函数不会再次运行。 -在上面这个例子中, `createInitialState` 有一个 `username` 参数。如果初始化函数不需要参数就可以计算出初始值,可以把 `useReducer` 的第二个参数改为 `null`。 +在上面这个例子中,`createInitialState` 有一个 `username` 参数。如果初始化函数不需要参数就可以计算出初始值,可以把 `useReducer` 的第二个参数改为 `null`。 #### 使用初始化函数 {/*passing-the-initializer-function*/} -这个示例使用了一个初始化函数,所以 `createInitialState` 函数只会在初次渲染的时候进行调用。即使因为你往输入框中输入内容导致组件重新渲染,初始化函数也不会被再次调用。 +这个示例使用了一个初始化函数,所以 `createInitialState` 函数只会在初次渲染的时候进行调用。即使往输入框中输入内容导致组件重新渲染,初始化函数也不会被再次调用。 @@ -847,7 +847,7 @@ export default function TodoList({ username }) { #### 直接传入初始值 {/*passing-the-initial-state-directly*/} -这个示例 **没有使用** 初始化函数,所以当你往输入框输入内容导致组件重新渲染的时候, `createInitialState` 函数就会执行。虽然在渲染结果上看没有什么区别,但是多余的逻辑会导致性能变差。 +这个示例 **没有使用** 初始化函数,所以当你往输入框输入内容导致组件重新渲染的时候,`createInitialState` 函数就会执行。虽然在渲染结果上看没有什么区别,但是多余的逻辑会导致性能变差。