Skip to content

Commit

Permalink
docs(cn): review and update
Browse files Browse the repository at this point in the history
  • Loading branch information
Yucohny authored Jul 12, 2023
1 parent dad4e42 commit e9140aa
Showing 1 changed file with 20 additions and 20 deletions.
40 changes: 20 additions & 20 deletions src/content/reference/react/useReducer.md
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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*/}
Expand All @@ -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 和初始化函数是纯函数(理应如此)就不会改变你的逻辑。其中一个调用结果会被忽略。
---
Expand All @@ -68,7 +68,7 @@ function handleClick() {
// ...
```
React 会调用 `reducer` 函数来更新 state,`reducer` 函数的参数就是当前的 state 和你传给 `dispatch` action。
React 会调用 `reducer` 函数以更新 state,`reducer` 函数的参数为当前的 state 与传递的 action。
#### 参数 {/*dispatch-parameters*/}
Expand All @@ -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';
Expand All @@ -111,7 +111,7 @@ function MyComponent() {
1. <CodeStep step={1}>当前的 state</CodeStep>,首次渲染时为你提供的 <CodeStep step={3}>初始值</CodeStep>。
2. <CodeStep step={2}>`dispatch` 函数</CodeStep>,让你可以根据交互修改 state。
为了更新屏幕上的内容,使用一个表示用户操作的 *action* 来调用 <CodeStep step={2}>`dispatch`</CodeStep> 函数:
为了更新屏幕上的内容,使用一个表示用户操作的 action 来调用 <CodeStep step={2}>`dispatch`</CodeStep> 函数:
```js [[2, 2, "dispatch"]]
function handleClick() {
Expand Down Expand Up @@ -157,7 +157,7 @@ button { display: block; margin-top: 10px; }
</Sandpack>
`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)。
---
Expand Down Expand Up @@ -193,7 +193,7 @@ function reducer(state, action) {
}
```

action 可以是任意类型,不过通常实现为存在 `type` 属性的对象。也就是说它需要携带计算新的 state 值所必须的数据。
action 可以是任意类型,不过通常至少是一个存在 `type` 属性的对象。也就是说它需要携带计算新的 state 值所必须的数据。

```js {5,9-12}
function Form() {
Expand All @@ -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) 来了解更多内容。

<Pitfall>

Expand Down Expand Up @@ -509,7 +509,7 @@ ul, li { margin: 0; padding: 0; }

<Solution />

#### 使用 Immer 编写简介的更新逻辑 {/*writing-concise-update-logic-with-immer*/}
#### 使用 Immer 编写简洁的更新逻辑 {/*writing-concise-update-logic-with-immer*/}

如果使用复制方法更新数组和对象让你不厌其烦,那么可以使用 [Immer](https://github.com/immerjs/use-immer#useimmerreducer) 这样的库来减少一些重复的样板代码。Immer 让你可以专注于逻辑,因为它在内部均使用复制方法来完成更新:

Expand Down Expand Up @@ -753,13 +753,13 @@ function TodoList({ username }) {

需要注意的是你传入的参数是 `createInitialState` 这个 **函数自身**,而不是执行 `createInitialState()` 后的返回值。这样传参就可以保证初始化函数不会再次运行。

在上面这个例子中, `createInitialState` 有一个 `username` 参数。如果初始化函数不需要参数就可以计算出初始值,可以把 `useReducer` 的第二个参数改为 `null`
在上面这个例子中,`createInitialState` 有一个 `username` 参数。如果初始化函数不需要参数就可以计算出初始值,可以把 `useReducer` 的第二个参数改为 `null`

<Recipes titleText="使用初始化函数和直接传入初始值的区别" titleId="examples-initializer">

#### 使用初始化函数 {/*passing-the-initializer-function*/}

这个示例使用了一个初始化函数,所以 `createInitialState` 函数只会在初次渲染的时候进行调用。即使因为你往输入框中输入内容导致组件重新渲染,初始化函数也不会被再次调用。
这个示例使用了一个初始化函数,所以 `createInitialState` 函数只会在初次渲染的时候进行调用。即使往输入框中输入内容导致组件重新渲染,初始化函数也不会被再次调用。

<Sandpack>

Expand Down Expand Up @@ -847,7 +847,7 @@ export default function TodoList({ username }) {

#### 直接传入初始值 {/*passing-the-initial-state-directly*/}

这个示例 **没有使用** 初始化函数,所以当你往输入框输入内容导致组件重新渲染的时候, `createInitialState` 函数就会执行。虽然在渲染结果上看没有什么区别,但是多余的逻辑会导致性能变差。
这个示例 **没有使用** 初始化函数,所以当你往输入框输入内容导致组件重新渲染的时候,`createInitialState` 函数就会执行。虽然在渲染结果上看没有什么区别,但是多余的逻辑会导致性能变差。

<Sandpack>

Expand Down

0 comments on commit e9140aa

Please sign in to comment.