From 636b141e7abd943d0d794bed38d173299cd80a52 Mon Sep 17 00:00:00 2001
From: qinhua <352484005@qq.com>
Date: Mon, 8 Nov 2021 19:28:17 +0800
Subject: [PATCH 1/7] docs(cn): managing-state
---
beta/src/pages/learn/managing-state.md | 254 ++++++++++++-------------
1 file changed, 126 insertions(+), 128 deletions(-)
diff --git a/beta/src/pages/learn/managing-state.md b/beta/src/pages/learn/managing-state.md
index 722468e4c7..1a069dc460 100644
--- a/beta/src/pages/learn/managing-state.md
+++ b/beta/src/pages/learn/managing-state.md
@@ -1,50 +1,53 @@
---
-title: Managing State
+title: 状态管理
+translators:
+ - qinhua
---
-As your application grows, it helps to be more intentional about how your state is organized and how the data flows between your components. Redundant or duplicate state is a common source of bugs. In this chapter, you'll learn how to structure your state well, how to keep your state update logic maintainable, and how to share state between distant components.
+随着你的应用不断变大,去刻意的关注应用状态如何组织,以及数据如何在组件之间流动会对你很有帮助。冗余或重复的状态往往是缺陷的根源。
+在本节中,你将学习如何组织好状态,如何保持状态更新逻辑的可维护性,以及如何跨组件共享状态。
-* [How to think about UI changes as state changes](/learn/reacting-to-input-with-state)
-* [How to structure state well](/learn/choosing-the-state-structure)
-* [How "lift state up" to share it between components](/learn/sharing-state-between-components)
-* [How to control whether the state gets preserved or reset](/learn/preserving-and-resetting-state)
-* [How to consolidate complex state logic in a function](/learn/extracting-state-logic-into-a-reducer)
-* [How to pass information without "prop drilling"](/learn/passing-data-deeply-with-context)
-* [How to scale state management as your app grows](/learn/scaling-up-with-reducer-and-context)
+* [如何将 UI 变更视为状态变更](/learn/reacting-to-input-with-state)
+* [如何组织好状态](/learn/choosing-the-state-structure)
+* [“状态提升”如何在组件之间共享状态](/learn/sharing-state-between-components)
+* [如何控制状态的保留或重置](/learn/preserving-and-resetting-state)
+* [如何在函数中整合复杂的状态逻辑](/learn/extracting-state-logic-into-a-reducer)
+* [如何避免使用“逐层props”传递数据](/learn/passing-data-deeply-with-context)
+* [如何随着应用的增长去扩展状态管理](/learn/scaling-up-with-reducer-and-context)
-## Reacting to input with state
+## 使用状态响应输入 {#reacting-to-input-with-state}
-With React, you won't modify the UI from code directly. For example, you won't write commands like "disable the button", "enable the button", "show the success message", etc. Instead, you will describe the UI you want to see for the different visual states of your component ("initial state", "typing state", "success state"), and then trigger the state changes in response to user input. This is similar to how designers think about UI.
+使用 React,你不用直接从代码层面修改 UI。例如,不用编写诸如“禁用按钮”、“启用按钮”、“显示成功消息”等命令。相反,你只需要描述组件在不同状态(“初始状态”、“输入状态”、“成功状态”)下希望展现的 UI,然后根据用户输入触发状态更改。这和设计师对 UI 的理解很相似。
-Here is a quiz form built using React. Note how it uses the `status` state variable to determine whether to enable or disable the submit button, and whether to show the success message instead.
+下面是一个使用 React 编写的反馈表单。请注意看它是如何使用 `status` 这个状态变量来决定启用或禁用提交按钮,以及是否显示成功消息的。
```js
import { useState } from 'react';
-export default function Form() {
- const [answer, setAnswer] = useState('');
+export default function FeedbackForm() {
+ const [message, setMessage] = useState('');
const [error, setError] = useState(null);
const [status, setStatus] = useState('typing');
if (status === 'success') {
- return
- In which city is there a billboard that turns air into drinkable water?
-
-
- >
+
);
}
-function submitForm(answer) {
- // Pretend it's hitting the network.
+function submitForm() {
+ // 模拟接口请求
return new Promise((resolve, reject) => {
setTimeout(() => {
- let shouldError = answer.toLowerCase() !== 'lima'
+ let shouldError = Math.random() > 0.5;
if (shouldError) {
- reject(new Error('Good guess but a wrong answer. Try again!'));
+ reject(new Error('出错了'));
} else {
resolve();
}
@@ -108,15 +105,15 @@ function submitForm(answer) {
-Read **[Reacting to Input with State](/learn/reacting-to-input-with-state)** to learn how to approach interactions with a state-driven mindset.
+阅读 **[用状态对输入作出响应](/learn/reacting-to-input-with-state)** 来学习如何以状态驱动的思维处理交互。
-## Choosing the state structure
+## 选择状态结构 {#choosing-the-state-structure}
-Structuring state well can make a difference between a component that is pleasant to modify and debug, and one that is a constant source of bugs. The most important principle is that state shouldn't contain redundant or duplicated information. If there's some unnecessary state, it's easy to forget to update it, and introduce bugs!
+良好的状态组织可以把易于修改和调试的组件与频繁出问题的组件区分开来。最重要的原则是,状态不应包含冗余或重复的信息。如果包含一些多余的状态,我们会很容易忘记去更新它,从而导致问题产生!
-For example, this form has a **redundant** `fullName` state variable:
+例如,这个表单有一个多余的 `fullName` 状态变量:
@@ -140,24 +137,23 @@ export default function Form() {
return (
<>
-
Let’s check you in
-
- Your ticket will be issued to: {fullName}
-
+
+ 您的全名是:{fullName}
+
>
);
}
@@ -169,7 +165,7 @@ label { display: block; margin-bottom: 5px; }
-You can remove it and simplify the code by calculating `fullName` while the component is rendering:
+你可以移除它并在组件渲染时通过计算 `fullName` 来简化代码:
@@ -192,24 +188,23 @@ export default function Form() {
return (
<>
-
Let’s check you in
-
- Your ticket will be issued to: {fullName}
-
+
+ 您的全名是:{fullName}
+
>
);
}
@@ -221,19 +216,17 @@ label { display: block; margin-bottom: 5px; }
-This might seem like a small change, but many bugs in React apps are fixed this way.
-
-Read **[Choosing the State Structure](/learn/choosing-the-state-structure)** to learn how to design the state shape to avoid bugs.
+阅读 **[选择状态结构](/learn/choosing-the-state-structure)** 来学习如何简化状态更新并避开常见问题。
-## Sharing state between components
+## 在组件间共享状态 {#sharing-state-between-components}
-Sometimes, you want the state of two components to always change together. To do it, remove state from both of them, move it to their closest common parent, and then pass it down to them via props. This is known as "lifting state up", and it's one of the most common things you will do writing React code.
+有时候,你希望两个组件的状态始终同步更改。要实现这一点,可以将相关状态从这两个组件上移除,并把状态放到它们的公共父级,再通过属性将状态传递给这两个组件。这被称为“状态提升”,这是编写 React 代码时常做的事。
-In this example, only one panel should be active at a time. To achieve this, instead of keeping the active state inside each individual panel, the parent component holds the state and specifies the props for its children.
+在以下示例中,要求每次只能激活一个面板。要实现这一点,父组件将保留状态并为其子组件指定属性,而不是将活动状态保留在每个面板中。
@@ -244,20 +237,20 @@ export default function Accordion() {
const [activeIndex, setActiveIndex] = useState(0);
return (
<>
-
Almaty, Kazakhstan
setActiveIndex(0)}
>
- With a population of about 2 million, Almaty is Kazakhstan's largest city. From 1929 to 1997, it was its capital city.
+ 牛奶、茶包和一根肉桂棒。
setActiveIndex(1)}
>
- The name comes from алма, the Kazakh word for "apple" and is often translated as "full of apples". In fact, the region surrounding Almaty is thought to be the ancestral home of the apple, and the wild Malus sieversii is considered a likely candidate for the ancestor of the modern domestic apple.
+ 把牛奶加热,然后把茶包放进锅里。
+ 加入肉桂棒。
>
);
@@ -276,7 +269,7 @@ function Panel({
{children}
) : (
)}
@@ -296,15 +289,15 @@ h3, p { margin: 5px 0px; }
-Read **[Sharing State Between Components](/learn/sharing-state-between-components)** to learn how to lift state up and keep components in sync.
+阅读 **[在组件间共享状态](/learn/sharing-state-between-components)** 来学习如何提升状态并保持组件同步。
-## Preserving and resetting state
+## 保留和重置状态 {#preserving-and-resetting-state}
-When you re-render a component, React needs to decide which parts of the tree to keep (and update), and which parts to discard or re-create from scratch. In most cases, React's automatic behavior works well enough. By default, React preserves the parts of the tree that "match up" with the previously rendered component tree.
+当你重新渲染一个组件时, React 需要决定组件树中的哪些部分要保留和更新,以及丢弃或重新创建。在大多数情况下, React 的自动处理机制已经做得足够好了。默认情况下,React 会保留树中与先前渲染的组件树“匹配”的部分。
-However, sometimes this is not what you want. For example, in this app, typing a message and then switching the recipient does not reset the input. This can make the user accidentally send a message to the wrong person:
+然而,有时这并不是你想要的。例如,在下面这个程序中,输入内容后再切换收件人并不会清空输入框。这可能会导致用户不小心发错消息:
@@ -371,7 +364,7 @@ export default function Chat({ contact }) {
onChange={e => setText(e.target.value)}
/>
-
+
);
}
@@ -399,7 +392,8 @@ textarea {
-React lets you override the default behavior, and *force* a component to reset its state by passing it a different `key`, like ``. This tells React that if the recipient is different, it should be considered a *different* `Chat` component that needs to be re-created from scratch with the new data (and UI like inputs). Now switching between the recipients always resets the input field--even though you render the same component.
+React 允许你覆盖默认行为,可通过向组件传递一个唯一 `key`(如 `` 来 *强制* 重置其状态。
+这告诉 React ,如果收件人不同,应将其作为一个 *不同的* `Chat` 组件,需要使用新数据和 UI(比如输入框)来重新创建它。现在,在接收者之间切换时就会重置输入框——即使渲染的是同一个组件。
@@ -466,7 +460,7 @@ export default function Chat({ contact }) {
onChange={e => setText(e.target.value)}
/>
-
+
);
}
@@ -496,13 +490,13 @@ textarea {
-Read **[Preserving and Resetting State](/learn/preserving-and-resetting-state)** to learn the lifetime of state and how to control it.
+阅读 **[保留和重置状态](/learn/preserving-and-resetting-state)** 来学习状态的生命周期以及如何控制它。
-## Extracting state logic into a reducer
+## 提取状态逻辑到 reducer 中 {#extracting-state-logic-into-a-reducer}
-Components with many state updates spread across many event handlers can get overwhelming. For these cases, you can consolidate all the state update logic outside your component in a single function, called "reducer." Your event handlers become concise because they only specify the user "actions." At the bottom of the file, the reducer function specifies how the state should update in response to each action!
+具有跨多个事件处理程序的多状态更新组件可能会令人不知所措。对于这种情况,你可以将组件外部的所有状态更新逻辑合并到一个称为“reducer”的函数中。这样,事件处理程序就会变得简洁,因为它们只需要指定用户的“操作”。在文件的底部,reducer 函数指定状态应该如何更新以响应每个操作!
@@ -541,7 +535,6 @@ export default function TaskBoard() {
return (
<>
-
{tasks.map(task => (
@@ -648,7 +641,7 @@ function Task({ task, onChange, onDelete }) {
});
}} />
>
);
@@ -657,7 +650,7 @@ function Task({ task, onChange, onDelete }) {
<>
{task.text}
>
);
@@ -676,7 +669,7 @@ function Task({ task, onChange, onDelete }) {
/>
{taskContent}
);
@@ -693,15 +686,15 @@ ul, li { margin: 0; padding: 0; }
-Read **[Extracting State Logic into a Reducer](/learn/extracting-state-logic-into-a-reducer)** to learn how to consolidate logic in the reducer function.
+阅读 **[提取状态逻辑到 reducer 中](/learn/extracting-state-logic-into-a-reducer)** 来学习如何在 reducer 函数中整合逻辑。
-## Passing data deeply with context
+## 使用 Context 进行深层数据传递 {#passing-data-deeply-with-context}
-Usually, you will pass information from a parent component to a child component via props. But passing props can become inconvenient if you need to pass some prop through many components, or if many components need the same information. Context lets the parent component make some information available to any component in the tree below it—no matter how deep it is—without passing it explicitly through props.
+通常,你会通过 props 将信息从父组件传递给子组件。但是,如果要在树中深入传递一些 prop,或者 UI 树中的许多组件需要相同的 prop,那么传递 prop 可能会变得很麻烦。Context 允许父组件将一些信息提供给它下面的任何组件,不管它有多深,而无需通过 props 显式传递。
-Here, the `Heading` component determines its heading level by "asking" the closest `Section` for its level. Each `Section` tracks its own level by asking the parent `Section` and adding one to it. Every `Section` provides information to all components below it without passing props--it does that through context.
+这里,`Heading` 组件通过“询问”最近的 `Section` 来确定其标题级别。每个 `Section` 通过询问父 `Section` 并向其添加一个来跟踪自己的级别。每个 `Section` 都向它下面的所有组件提供信息,而不需要传递 props——它是通过 Context 来实现的。
@@ -771,7 +764,7 @@ export default function Heading({ children }) {
case 6:
return
{children}
;
default:
- throw Error('Unknown level: ' + level);
+ throw Error('未知级别:' + level);
}
}
```
@@ -795,27 +788,26 @@ export const LevelContext = createContext(0);
-Read **[Passing Data Deeply with Context](/learn/passing-data-deeply-with-context)** to learn about using context as an alternative to passing props.
+阅读 **[使用 Context 进行深层数据传递](/learn/passing-data-deeply-with-context)** 来学习如何使用上下文代替属性传递。
-## Scaling up with reducer and context
+## 使用 Reducer 和 Context 进行状态扩展 {#scaling-up-with-reducer-and-context}
-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 帮助你将信息深入传递给其他组件。你可以将 reducers 和 context 组合在一起使用,以管理复杂应用的状态。
-With this approach, a parent component with complex state manages it with a reducer. Other components anywhere deep in the tree can read its state via context. They can also dispatch actions to update that state.
+基于这种方法,使用 reducer 来管理一个具有复杂状态的父组件。组件树中任意位置的其他组件都可以通过上下文读取其状态。还可以派发操作来更新状态。
```js App.js
import AddTask from './AddTask.js';
import TaskList from './TaskList.js';
-import { TasksProvider } from './TasksContext.js';
+import { TasksProvider } from './TaskBoardContext.js';
export default function TaskBoard() {
return (
-
Day off in Kyoto
@@ -823,10 +815,15 @@ export default function TaskBoard() {
}
```
-```js TasksContext.js
-import { createContext, useContext, useReducer } from 'react';
+```js TaskBoardContext.js
+import {
+ createContext,
+ useContext,
+ useReducer
+} from 'react';
+
+const TaskBoardContext = createContext(null);
-const TasksContext = createContext(null);
const TasksDispatchContext = createContext(null);
export function TasksProvider({ children }) {
@@ -836,18 +833,18 @@ export function TasksProvider({ children }) {
);
return (
-
+
{children}
-
+
);
}
export function useTasks() {
- return useContext(TasksContext);
+ return useContext(TaskBoardContext);
}
export function useTasksDispatch() {
@@ -876,21 +873,21 @@ function tasksReducer(tasks, action) {
return tasks.filter(t => t.id !== action.id);
}
default: {
- throw Error('Unknown action: ' + action.type);
+ throw Error('未知操作:' + action.type);
}
}
}
const initialTasks = [
- { id: 0, text: 'Philosopher’s Path', done: true },
- { id: 1, text: 'Visit the temple', done: false },
- { id: 2, text: 'Drink matcha', done: false }
+ { id: 0, text: '买牛奶', done: true },
+ { id: 1, text: '吃玉米饼', done: false },
+ { id: 2, text: '泡茶', done: false },
];
```
```js AddTask.js
import { useState, useContext } from 'react';
-import { useTasksDispatch } from './TasksContext.js';
+import { useTasksDispatch } from './TaskBoardContext.js';
export default function AddTask({ onAddTask }) {
const [text, setText] = useState('');
@@ -898,7 +895,7 @@ export default function AddTask({ onAddTask }) {
return (
<>
setText(e.target.value)}
/>
@@ -909,7 +906,7 @@ export default function AddTask({ onAddTask }) {
id: nextId++,
text: text,
});
- }}>Add
+ }}>添加
>
);
}
@@ -919,7 +916,7 @@ let nextId = 3;
```js TaskList.js
import { useState, useContext } from 'react';
-import { useTasks, useTasksDispatch } from './TasksContext.js';
+import { useTasks, useTasksDispatch } from './TaskBoardContext.js';
export default function TaskList() {
const tasks = useTasks();
@@ -953,7 +950,7 @@ function Task({ task }) {
});
}} />
>
);
@@ -962,7 +959,7 @@ function Task({ task }) {
<>
{task.text}
>
);
@@ -989,7 +986,7 @@ function Task({ task }) {
id: task.id
});
}}>
- Delete
+ 删除
);
@@ -1004,14 +1001,15 @@ ul, li { margin: 0; padding: 0; }
+
-Read **[Scaling Up with Reducer and Context](/learn/scaling-up-with-reducer-and-context)** to learn how state management scales in a growing app.
+阅读 **[使用 Reducer 和 Context 进行扩展](/learn/scaling-up-with-reducer-and-context)** 来学习如何在不断增长的应用程序中扩展状态管理。
-## What's next?
+## 下节预告 {#what-is-next}
-Head over to [Reacting to Input with State](/learn/reacting-to-input-with-state) to start reading this chapter page by page!
+跳转到 [使用状态响应输入](/learn/reacting-to-input-with-state) 这一节并开始一页页的阅读!
-Or, if you're already familiar with these topics, why not read about [Escape Hatches](/learn/escape-hatches)?
+当然,如果你已经熟悉了这些内容,可以去读一读 [Escape Hatches](/learn/escape-hatches)?
\ No newline at end of file
From 5070a2f94b1c3491a0469994ca626671b3eaaee5 Mon Sep 17 00:00:00 2001
From: qinhua <352484005@qq.com>
Date: Sat, 11 Dec 2021 21:44:02 +0800
Subject: [PATCH 2/7] resolve conversation
---
beta/src/pages/learn/managing-state.md | 26 +++++++++++++-------------
1 file changed, 13 insertions(+), 13 deletions(-)
diff --git a/beta/src/pages/learn/managing-state.md b/beta/src/pages/learn/managing-state.md
index 1984ddc076..9c5adc7d01 100644
--- a/beta/src/pages/learn/managing-state.md
+++ b/beta/src/pages/learn/managing-state.md
@@ -6,7 +6,7 @@ translators:
-随着你的应用不断变大,去刻意的关注应用状态如何组织,以及数据如何在组件之间流动会对你很有帮助。冗余或重复的状态往往是缺陷的根源。
+随着你的应用不断变大,更有意识的去关注应用状态如何组织,以及数据如何在组件之间流动会对你很有帮助。冗余或重复的状态往往是缺陷的根源。
在本节中,你将学习如何组织好状态,如何保持状态更新逻辑的可维护性,以及如何跨组件共享状态。
@@ -15,10 +15,10 @@ translators:
* [如何将 UI 变更视为状态变更](/learn/reacting-to-input-with-state)
* [如何组织好状态](/learn/choosing-the-state-structure)
-* [“状态提升”如何在组件之间共享状态](/learn/sharing-state-between-components)
+* [如何使用“状态提升”在组件之间共享状态](/learn/sharing-state-between-components)
* [如何控制状态的保留或重置](/learn/preserving-and-resetting-state)
* [如何在函数中整合复杂的状态逻辑](/learn/extracting-state-logic-into-a-reducer)
-* [如何避免使用“逐层props”传递数据](/learn/passing-data-deeply-with-context)
+* [如何避免数据通过 prop 逐级透传](/learn/passing-data-deeply-with-context)
* [如何随着应用的增长去扩展状态管理](/learn/scaling-up-with-reducer-and-context)
@@ -111,7 +111,7 @@ function submitForm() {
## 选择状态结构 {/*choosing-the-state-structure*/}
-良好的状态组织可以把易于修改和调试的组件与频繁出问题的组件区分开来。最重要的原则是,状态不应包含冗余或重复的信息。如果包含一些多余的状态,我们会很容易忘记去更新它,从而导致问题产生!
+良好的状态组织,可以区分开易于修改和调试的组件与频繁出问题的组件。最重要的原则是,状态不应包含冗余或重复的信息。如果包含一些多余的状态,我们会很容易忘记去更新它,从而导致问题产生!
例如,这个表单有一个多余的 `fullName` 状态变量:
@@ -203,7 +203,7 @@ export default function Form() {
/>