Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Beta] docs(cn): translate scaling-up-with-reducer-and-context #694

Merged
merged 24 commits into from
Feb 21, 2022
Merged
Changes from 22 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
e6146c6
docs(cn): scaling-up-with-reducer-and-context
ikaite Dec 11, 2021
ded0107
docs(cn): scaling-up-with-reducer-and-context
ikaite Dec 19, 2021
3d8dc6c
docs(cn): scaling-up-with-reducer-and-context
ikaite Dec 19, 2021
776b471
Apply suggestions from code review
ikaite Dec 27, 2021
beadfaa
Update scaling-up-with-reducer-and-context.md
ikaite Dec 27, 2021
3494e85
Update beta/src/pages/learn/scaling-up-with-reducer-and-context.md
ikaite Jan 3, 2022
d3d3d31
Update beta/src/pages/learn/scaling-up-with-reducer-and-context.md
ikaite Jan 3, 2022
ba2b71b
Update beta/src/pages/learn/scaling-up-with-reducer-and-context.md
ikaite Jan 3, 2022
c380ffb
Update beta/src/pages/learn/scaling-up-with-reducer-and-context.md
ikaite Jan 3, 2022
d9a222e
Update beta/src/pages/learn/scaling-up-with-reducer-and-context.md
ikaite Jan 3, 2022
abb3957
Update beta/src/pages/learn/scaling-up-with-reducer-and-context.md
ikaite Jan 3, 2022
dd78a37
Update beta/src/pages/learn/scaling-up-with-reducer-and-context.md
ikaite Jan 3, 2022
21a8a43
Update beta/src/pages/learn/scaling-up-with-reducer-and-context.md
ikaite Jan 3, 2022
dfec359
Update beta/src/pages/learn/scaling-up-with-reducer-and-context.md
ikaite Jan 3, 2022
4345563
Update beta/src/pages/learn/scaling-up-with-reducer-and-context.md
ikaite Jan 3, 2022
e5c6c34
Update beta/src/pages/learn/scaling-up-with-reducer-and-context.md
ikaite Jan 3, 2022
2dcef4e
Update beta/src/pages/learn/scaling-up-with-reducer-and-context.md
ikaite Jan 3, 2022
ad99d4b
Update scaling-up-with-reducer-and-context.md
ikaite Jan 5, 2022
6b5d841
Update beta/src/pages/learn/scaling-up-with-reducer-and-context.md
ikaite Feb 7, 2022
0a3281c
Apply suggestions from code review
KnowsCount Feb 8, 2022
ee21698
Merge branch 'main' into scaling-up-with-reducer-and-context
KnowsCount Feb 8, 2022
3e2c27e
Fix some spacing issues
KnowsCount Feb 13, 2022
2b1cc19
Update scaling-up-with-reducer-and-context.md
ikaite Feb 20, 2022
411eed8
Update beta/src/pages/learn/scaling-up-with-reducer-and-context.md
QC-L Feb 21, 2022
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
109 changes: 55 additions & 54 deletions beta/src/pages/learn/scaling-up-with-reducer-and-context.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
---
title: Scaling Up with Reducer and Context
title: 使用 Reducer Context 来拓展你的应用
ikaite marked this conversation as resolved.
Show resolved Hide resolved
---

<Intro>

Reducers let you consolidate a component's state update logic. Context lets you pass information deep down to other components. You can combine reducers and context together to manage state of a complex screen.
Reducer 可以整合组件的状态更新逻辑。Context 可以将信息深入传递给其他组件。你可以组合使用它们来共同管理一个复杂页面的状态。

</Intro>

<YouWillLearn>

* How to combine a reducer with context
* How to avoid passing state and dispatch through props
* How to keep context and state logic in a separate file
* 如何结合使用 reducer context
* 如何去避免通过 props 传递 state dispatch
* 如何将 context 和状态逻辑保存在一个单独的文件中

</YouWillLearn>

## Combining a reducer with context {/*combining-a-reducer-with-context*/}
## 结合使用 reducer context {/*combining-a-reducer-with-context*/}

In this example from [the introduction to reducers](/learn/extracting-state-logic-into-a-reducer), the state is managed by a reducer. The reducer function contains all of the state update logic and is declared at the bottom of this file:
在 [reducer 介绍](/learn/extracting-state-logic-into-a-reducer) 的例子里面,状态被 reducer 所管理。reducer 函数包含了所有的状态更新逻辑并在此文件的底部声明:

<Sandpack>

Expand Down Expand Up @@ -207,8 +207,9 @@ ul, li { margin: 0; padding: 0; }

</Sandpack>

A reducer helps keep the event handlers short and concise. However, as your app grows, you might run into another difficulty. **Currently, the `tasks` state and the `dispatch` function are only available in the top-level `TaskApp` component.** To let other components read the list of tasks or change it, you have to explicitly [pass down](/learn/passing-props-to-a-component) the current state and the event handlers that change it as props.
Reducer 有助于保持事件处理程序的简短明了。但随着应用规模越来越庞大,你就可能会遇到别的困难。**目前,`tasks` 状态和 `dispatch` 函数仅在顶级 `TaskApp` 组件中可用**。要让其他组件读取任务列表或更改它,你必须显式 [传递](/learn/passing-props-to-a-component) 当前状态和将其更改为 props 的事件处理程序。

例如,`TaskApp` 将 一系列 task 和事件处理程序传递给 `TaskList`:
For example, `TaskApp` passes a list of tasks and the event handlers to `TaskList`:

```js
Expand All @@ -219,7 +220,7 @@ For example, `TaskApp` passes a list of tasks and the event handlers to `TaskLis
/>
```

And `TaskList` passes the event handlers to `Task`:
`TaskList` 将事件处理程序传递给 `Task`

```js
<Task
Expand All @@ -229,34 +230,34 @@ And `TaskList` passes the event handlers to `Task`:
/>
```

In a small example like this, this works well, but if you have tens or hundreds of components in the middle, passing down all state and functions can be quite frustrating!
在像这样的小示例里这样做没什么问题,但是如果你有成千上百个组件,传递所有状态和函数可能会非常麻烦!

<!--(TODO: illustration of prop drilling)-->

This is why, as an alternative to passing them through props, you might want to put both the `tasks` state and the `dispatch` function [into context](/learn/passing-data-deeply-with-context). **This way, any component below `TaskApp` in the tree can read the tasks and dispatch actions without the repetitive "prop drilling".**
这就是为什么,比起通过 props 传递它们,你可能想把 `tasks` 状态和 `dispatch` 函数都 [放入 context](/learn/passing-data-deeply-with-context)。**这样,所有的在 `TaskApp` 组件树之下的组件都不必一直往下传 props 而可以直接读取 tasks dispatch 函数**。

<!--(TODO: illustration of context)-->

Here is how you can combine a reducer with context:
下面将介绍如何结合使用 reducer context

1. **Create** the context.
2. **Put** state and dispatch into context.
3. **Use** context anywhere in the tree.
1. **创建** context
2. state dispatch **放入** context
3. 在组件树的任何地方 **使用** context

### Step 1: Create the context {/*step-1-create-the-context*/}
### 第一步: 创建 context {/*step-1-create-the-context*/}

The `useReducer` Hook returns the current `tasks` and the `dispatch` function that lets you update them:
`useReducer` 返回当前的 `tasks` `dispatch` 函数来让你更新它们:

```js
const [tasks, dispatch] = useReducer(tasksReducer, initialTasks);
```

To pass them down the tree, you will [create](/learn/passing-data-deeply-with-context#step-2-use-the-context) two separate contexts:
为了将它们从组件树往下传,你将 [创建](/learn/passing-data-deeply-with-context#step-2-use-the-context) 两个不同的 context:

- `TasksContext` provides the current list of tasks.
- `TasksDispatchContext` provides the function that lets components dispatch actions.
- `TasksContext` 提供当前的 tasks 列表。
- `TasksDispatchContext` 提供了一个函数可以让组件分发动作。

Export them from a separate file so that you can later import them from other files:
将它们从单独的文件导出,以便以后可以从其他文件导入它们:

<Sandpack>

Expand Down Expand Up @@ -452,11 +453,11 @@ ul, li { margin: 0; padding: 0; }

</Sandpack>

Here, you're passing `null` as the default value to both contexts. The actual values will be provided by the `TaskApp` component.
在这里,你把 `null` 作为默认值传递给两个 context。实际值是由 `TaskApp` 组件提供的。

### Step 2: Put state and dispatch into context {/*step-2-put-state-and-dispatch-into-context*/}
### 第二步: 将 state dispatch 函数 放入 context {/*step-2-put-state-and-dispatch-into-context*/}

Now you can import both contexts in your `TaskApp` component. Take the `tasks` and `dispatch` returned by `useReducer()` and [provide them](/learn/passing-data-deeply-with-context#step-3-provide-the-context) to the entire tree below:
现在,你可以将所有的 context 导入 `TaskApp` 组件。获取 `useReducer()` 返回的 `tasks` `dispatch` 并将它们 [提供](/learn/passing-data-deeply-with-context#step-3-provide-the-context) 给整个组件树:

```js {4,7-8}
import { TasksContext, TasksDispatchContext } from './TasksContext.js';
Expand All @@ -474,7 +475,7 @@ export default function TaskApp() {
}
```

For now, you pass the information both via props and in context:
现在,你可以同时通过 props context 传递信息:

<Sandpack>

Expand Down Expand Up @@ -673,11 +674,11 @@ ul, li { margin: 0; padding: 0; }

</Sandpack>

In the next step, you will remove prop passing.
在下一步中,你将删除通过 props 传递的代码。

### Step 3: Use context anywhere in the tree {/*step-3-use-context-anywhere-in-the-tree*/}
### Step 3: 在组件树中的任何地方使用 context {/*step-3-use-context-anywhere-in-the-tree*/}

Now you don't need to pass the list of tasks or the event handlers down the tree:
现在你不需要将 tasks 和事件处理程序在组件树中传递:

```js {4-5}
<TasksContext.Provider value={tasks}>
Expand All @@ -689,15 +690,15 @@ Now you don't need to pass the list of tasks or the event handlers down the tree
</TasksContext.Provider>
```

Instead, any component that needs the task list can read it from the `TaskContext`:
相反,任何需要 tasks 的组件都可以从 `TaskContext` 中读取它:

```js {2}
export default function TaskList() {
const tasks = useContext(TasksContext);
// ...
```

To update the task list, any component can read the `dispatch` function from context and call it:
任何组件都可以从 context 中读取 `dispatch` 函数并调用它,从而更新任务列表:

```js {3,9-13}
export default function AddTask({ onAddTask }) {
Expand All @@ -717,7 +718,7 @@ export default function AddTask({ onAddTask }) {
// ...
```

**The `TaskApp` component does not pass any event handlers down, and the `TaskList` does not pass any event handlers to the `Task` component either.** Each component reads the context that it needs:
**`TaskApp` 组件不会向下传递任何事件处理程序,`TaskList` 也不会**。每个组件都会读取它需要的 context

<Sandpack>

Expand Down Expand Up @@ -901,11 +902,11 @@ ul, li { margin: 0; padding: 0; }

</Sandpack>

**The state still "lives" in the top-level `TaskApp` component, managed with `useReducer`.** But its `tasks` and `dispatch` are now available to every component below in the tree by importing and using these contexts.
**state 仍然 “存在于” 顶层 `Task` 组件中,由 `useReducer` 进行管理**。不过,组件树里的组件只要导入这些 context 之后就可以获取 `tasks` `dispatch`

## Moving all wiring into a single file {/*moving-all-wiring-into-a-single-file*/}
## 将相关逻辑迁移到一个文件当中 {/*moving-all-wiring-into-a-single-file*/}

You don't have to do this, but you could further declutter the components by moving both reducer and context into a single file. Currently, `TasksContext.js` contains only two context declarations:
这不是必须的,但你可以通过将 reducer context 移动到单个文件中来进一步整理组件。目前,“TasksContext.js” 仅包含两个 context 声明:

```js
import { createContext } from 'react';
Expand All @@ -914,11 +915,11 @@ export const TasksContext = createContext(null);
export const TasksDispatchContext = createContext(null);
```

This file is about to get crowded! You'll move the reducer into that same file. Then you'll declare a new `TasksProvider` component in the same file. This component will tie all the pieces together:
来给这个文件添加更多代码!将 reducer 移动到此文件中,然后声明一个新的 `TasksProvider` 组件。此组件将所有部分连接在一起:

1. It will manage the state with a reducer.
2. It will provide both contexts to components below.
3. It will [take `children` as a prop](/learn/passing-props-to-a-component#passing-jsx-as-children) so you can pass JSX to it.
1. 它将管理 reducer 的状态。
2. 它将提供现有的 context 给组件树。
3. 它将 [把 `children` 作为 prop](/learn/passing-props-to-a-component#passing-jsx-as-children),所以你可以传递 JSX

```js
export function TasksProvider({ children }) {
Expand All @@ -934,7 +935,7 @@ export function TasksProvider({ children }) {
}
```

**This removes all the complexity and wiring from your `TaskApp` component:**
**这将使 `TaskApp` 组件更加直观:**

<Sandpack>

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

</Sandpack>

You can also export functions that _use_ the context from `TasksContext.js`:
你也可以从 `TasksContext.js` 中导出使用 context 的函数:

```js
export function useTasks() {
Expand All @@ -1137,14 +1138,14 @@ export function useTasksDispatch() {
}
```

When a component needs to read context, it can do it through these functions:
组件可以通过以下函数读取 context

```js {5-7}
const tasks = useTasks();
const dispatch = useTasksDispatch();
```

This doesn't change the behavior in any way, but it lets you later split these contexts further or add some logic to these functions. **Now all of the context and reducer wiring is in `TasksContext.js`. This keeps the components clean and uncluttered, focused on what they display rather than where they get the data:**
这不会改变任何行为,但它会允许你之后进一步分割这些 context 或向这些函数添加一些逻辑。**现在所有的 context reducer 连接部分都在 `TasksContext.js` 中。这保持了组件的干净和整洁,让我们专注于它们显示的内容,而不是它们从哪里获得数据:**

<Sandpack>

Expand Down Expand Up @@ -1344,23 +1345,23 @@ ul, li { margin: 0; padding: 0; }

</Sandpack>

You can think of `TasksProvider` as a part of the screen that knows how to deal with tasks, `useTasks` as a way to read them, and `useTasksDispatch` as a way to update them from any component below in the tree.
你可以将 `TasksProvider` 视为页面的一部分,它知道如何处理 tasks`useTasks` 用来读取它们,`useTasksDispatch` 用来从组件树下的任何组件更新它们。

> Functions like `useTasks` and `useTasksDispatch` are called **[Custom Hooks](/learn/reusing-logic-with-custom-hooks).** Your function is considered a custom Hook if its name starts with `use`. This lets you use other Hooks, like `useContext`, inside it.
> `useTasks` `useTasksDispatch` 这样的函数被称为 **[自定义 Hook](/learn/reusing-logic-with-custom-hooks)** 如果你的函数名以 `use` 开头,它就被认为是一个自定义 Hook。这让你可以使用其他 Hook,比如 `useContext`

As your app grows, you may have many context-reducer pairs like this. This is a powerful way to scale your app and [lift state up](/learn/sharing-state-between-components) without too much work whenever you want to access the data deep in the tree.
随着应用的增长,你可能会有许多这样的 context 和 reducer 的组合。这是一种强大的拓展应用并 [提升状态](/learn/sharing-state-between-components) 的方式,让你在组件树深处访问数据时无需进行太多工作。

<Recap>

- You can combine reducer with context to let any component read and update state above it.
- To provide state and the dispatch function to components below:
1. Create two contexts (for state and for dispatch functions).
2. Provide both contexts from the component that uses the reducer.
3. Use either context from components that need to read them.
- You can further declutter the components by moving all wiring into one file.
- You can export a component like `TasksProvider` that provides context.
- You can also export custom Hooks like `useTasks` and `useTasksDispatch` to read it.
- You can have many context-reducer pairs like this in your app.
- 你可以将 reducer context 相结合,让任何组件读取和更新它的状态。
- 为子组件提供 state dispatch 函数:
1. 创建两个 context (一个用于 state,一个用于 dispatch 函数)。
2. 让组件的 context 使用 reducer
3. 使用组件中需要读取的 context
- 你可以通过将所有传递信息的代码移动到单个文件中来进一步整理组件。
- 你可以导出一个像 `TasksProvider` 可以提供 context 的组件。
- 你也可以导出像 `useTasks` `useTasksDispatch` 这样的自定义 Hook。
- 你可以在你的应用程序中大量使用 context 和 reducer 的组合。

</Recap>