From 394fbef73e1df8c6bf5b534a0123555c8b2cfd89 Mon Sep 17 00:00:00 2001 From: zhaozhiwei Date: Sat, 6 Nov 2021 11:14:20 +0800 Subject: [PATCH 1/8] docs(cn): state-a-components-memory --- .../pages/learn/state-a-components-memory.md | 62 ++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/beta/src/pages/learn/state-a-components-memory.md b/beta/src/pages/learn/state-a-components-memory.md index d0ee608e42..174cb4c86a 100644 --- a/beta/src/pages/learn/state-a-components-memory.md +++ b/beta/src/pages/learn/state-a-components-memory.md @@ -1,15 +1,22 @@ --- title: "State: A Component's Memory" +translators: + - 7ooz --- +作为交互的结果,组件通常需要更改屏幕上的内容。输入表单应该更新输入字段,单击图片轮播上的“下一张”应该更改显示的图片,单击“购买”应该将商品放入购物车。组件需要“记忆”信息:当前输入值、当前图片、购物车。在 React 中,这种组件特有的内存称为 **state**。 Components often need to change what's on the screen as a result of an interaction. Typing into the form should update the input field, clicking "next" on an image carousel should change which image is displayed, clicking "buy" should put a product in the shopping cart. Components need to "remember" things: the current input value, the current image, the shopping cart. In React, this kind of component-specific memory is called **state**. +* 如何使用 [`useState`](/reference/usestate) Hook 添加 state 变量 +* `useState` Hook 返回哪一对值 +* 如何添加多个 state 变量 +* 为什么 state 被称作局部的 * How to add a state variable with the [`useState`](/reference/usestate) Hook * What pair of values the `useState` Hook returns * How to add more than one state variable @@ -19,6 +26,7 @@ Components often need to change what's on the screen as a result of an interacti ## When a regular variable isn’t enough +以下是一个渲染雕塑图片的组件。单击“下一步”按钮应该将 `index` 更改为 `1`,再次点击更改为 `2`,以此类推显示下一个雕塑。但是,这**行不通**(你可以尝试一下!): Here's a component that renders a sculpture image. Clicking the "Next" button should show the next sculpture by changing the `index` to `1`, then `2`, and so on. However, this **won't work** (you can try it!): @@ -151,45 +159,61 @@ button { +`handleClick()` 事件处理函数正在更新局部变量 `index`。但是有两件事阻止了这种变化是可见的: The `handleClick()` event handler is updating a local variable, `index`. But two things prevent that change from being visible: +1. **局部变量不会在多次渲染间保存。** 当 React 第二次渲染这个组件时,它会从头开始渲染——不考虑对局部变量的任何更改。 +2. **对局部变量的更改不会触发渲染。** React 没有意识到它需要使用新数据再次渲染组件。 1. **Local variables don't persist between renders.** When React renders this component a second time, it renders it from scratch—it doesn't consider any changes to the local variables. 2. **Changes to local variables won't trigger renders.** React doesn't realize it needs to render the component again with the new data. +要使用新数据更新组件,需要做两件事: To update a component with new data, two things need to happen: +1. **保留**渲染之间的数据。 +2. **触发** React 使用新数据渲染组件(重新渲染)。 1. **Retain** the data between renders. 2. **Trigger** React to render the component with new data (re-rendering). +[`useState`](/reference/usestate) Hook 提供了这两个功能: The [`useState`](/reference/usestate) Hook provides those two things: +1. **State 变量** 用于保留渲染之间的数据。 +2. **State setter 函数** 更新变量并触发 React 再次渲染组件。 1. A **state variable** to retain the data between renders. 2. A **state setter function** to update the variable and trigger React to render the component again. ## Adding a state variable +要添加 state 变量,请从文件顶部的 React 导入 `useState`: To add a state variable, import `useState` from React at the top of the file: ```js import { useState } from 'react'; ``` +然后,替换掉这一行: Then, replace this line: ```js let index = 0; ``` +修改为 with ```js const [index, setIndex] = useState(0); -```` +``` +`index` 是一个 state 变量,`setIndex` 是 setter 函数。 `index` is a state variable and `setIndex` is the setter function. + +> 这里的 `[` 和 `]` 语法称为[数组解构](/learn/a-javascript-refresher#array-destructuring),它允许你从数组中读取值。 `useState` 返回的数组总是正好有两个项。 > The `[` and `]` syntax here is called [array destructuring](/learn/a-javascript-refresher#array-destructuring) and it lets you read values from an array. The array returned by `useState` always has exactly two items. +以下展示了它们在 `handleClick()` 中是如何协同工作的: This is how they work together in `handleClick()`: ```js @@ -198,6 +222,7 @@ function handleClick() { } ``` +现在点击“下一步”按钮切换当前雕塑: Now clicking the "Next" button switches the current sculpture: @@ -333,43 +358,59 @@ button { ### Meet your first Hook +在 React 中,`useState` 以及任何其他以“`use`”开头的函数都被称为 **Hook**。 In React, `useState`, as well as any other function starting with "`use`," is called a **Hook**. +Hooks 是特殊的函数,只有在 React [渲染](/learn/render-and-commit#step-1-trigger-a-render) 时才可用(我们将在下一节详细介绍)。它们让你“hook into”到不同的 React 特性。 Hooks are special functions that are only available while React is [rendering](/learn/render-and-commit#step-1-trigger-a-render) (which we'll get into in more detail on the next page). They let you "hook into" different React features. +State 只是这些功能之一,但你稍后会遇到其他 Hook。 State is just one of those features, but you will meet the other Hooks later. +**Hooks——以`use`开头的函数——只能在组件或[自定义 Hooks](/learn/reusing-logic-with-custom-hooks)的顶层调用。**你不能调用条件、循环或其他嵌套函数内的 Hooks。Hooks 是函数,但将它们视为关于组件需求的无条件声明会很有帮助。你在组件顶部“使用”React 功能类似于在文件顶部“导入”模块的方式。 **Hooks—functions starting with `use`—can only be called at the top level of your components or [your own Hooks](/learn/reusing-logic-with-custom-hooks).** You can't call Hooks inside conditions, loops, or other nested functions. Hooks are functions, but it's helpful to think of them as unconditional declarations about your component's needs. You "use" React features at the top of your component similar to how you "import" modules at the top of your file. ### Anatomy of `useState` +当你调用 [`useState`](/reference/usestate) 时,你是在告诉 React 你想让这个组件记住一些东西: When you call [`useState`](/reference/usestate), you are telling React that you want this component to remember something: ```js const [index, setIndex] = useState(0); ``` +在这个例子里,你希望 React 记住 `index`。 In this case, you want React to remember `index`. +> 惯例是将这对命名为 `const [thing, setThing]`。你可以将其命名为任何你喜欢的名称,但约定俗成能使跨项目的事情更容易理解。 > The convention is to name this pair like `const [thing, setThing]`. You could name it anything you like, but conventions make things easier to understand across projects. +`useState` 的唯一参数是状态变量的**初始值**。在这个例子中,`index` 的初始值被设置为 `useState(0)` 的 `0`。 The only argument to `useState` is the **initial value** of your state variable. In this example, the `index`'s initial value is set to `0` with `useState(0)`. +每次你的组件渲染时,`useState` 都会给你一个包含两个值的数组: Every time your component renders, `useState` gives you an array containing two values: +1. **state 变量** (`index`) 与你存储的值。 +2. **state setter 函数** (`setIndex`) 可以更新状态变量并触发 React 重新渲染组件。 1. The **state variable** (`index`) with the value you stored. 2. The **state setter function** (`setIndex`) which can update the state variable and trigger React to render the component again. +这是实际发生的情况: Here's how that happens in action: ```js const [index, setIndex] = useState(0); ``` +1. **组件第一次渲染。** 因为你将 `0` 作为 `index` 的初始值传递给 `useState`,它将返回 `[0, setIndex]`。 React 记得 `0` 是最新的状态值。 +2. **你更新了状态。**当用户点击按钮时,它会调用`setIndex(index + 1)`。 `index` 是 `0`,所以它是 `setIndex(1)`。这告诉 React 现在记住 `index` 是 `1` 并触发另一个渲染。 +3. **组件第二次渲染。** React 仍然看到 `useState(0)`,但是因为 React *记住* 你将 `index` 设置为 `1`,它返回 `[1, setIndex]`。 +4. 以此类推! 1. **Your component renders the first time.** Because you passed `0` to `useState` as the initial value for `index`, it will return `[0, setIndex]`. React remembers `0` is the latest state value. 2. **You update the state.** When a user clicks the button, it calls `setIndex(index + 1)`. `index` is `0`, so it's `setIndex(1)`. This tells React to remember `index` is `1` now and triggers another render. 3. **Your component's second render.** React still sees `useState(0)`, but because React *remembers* that you set `index` to `1`, it returns `[1, setIndex]` instead. @@ -377,6 +418,7 @@ const [index, setIndex] = useState(0); ## Giving a component multiple state variables +您可以在一个组件中拥有任意多种类型的状态变量。该组件有两个状态变量,一个数字 `index` 和一个布尔值 `showMore`,当您单击“显示详细信息”时会切换该变量: You can have as many state variables of as many types as you like in one component. This component has two state variables, a number `index` and a boolean `showMore` that's toggled when you click "Show details": @@ -516,16 +558,21 @@ button { +如果它们的 state 不相关,那么拥有多个 state 变量是一个好主意,例如本例中的 `index` 和 `showMore`。但是,如果您发现经常一起更改两个 state 变量,则最好将它们合并为一个。例如,如果您有一个包含多个字段的表单,那么拥有一个保存对象的单个 state 变量比每个字段的 state 变量更方便。 [Choosing the State Structure](/learn/choosing-the-state-structure)在这方面有更多提示。 It is a good idea to have multiple state variables if their state is unrelated, like `index` and `showMore` in this example. But if you find that you often change two state variables together, it might be better to combine them into a single one. For example, if you have a form with many fields, it's more convenient to have a single state variable that holds an object than state variable per field. [Choosing the State Structure](/learn/choosing-the-state-structure) has more tips on this. +您可能已经注意到,`useState` 调用没有收到关于它引用的*哪个* state 变量的任何信息。没有传递给`useState` 的“标识符”,那么它如何知道要返回哪个 state 变量呢?它是否依赖于解析函数之类的魔法?答案是否。 You might have noticed that the `useState` call does not receive any information about *which* state variable it refers to. There is no "identifier" that is passed to `useState`, so how does it know which of the state variables to return? Does it rely on some magic like parsing your functions? The answer is no. +相反,为了启用其简洁的语法,Hooks **依赖于同一组件的每次渲染**的稳定调用顺序。这在实践中很有效,因为如果你遵循上面的规则(“只在顶层调用 Hooks”),Hooks 将始终以相同的顺序被调用。此外,[linter 插件](https://www.npmjs.com/package/eslint-plugin-react-hooks) 可以捕获大多数错误。 Instead, to enable their concise syntax, Hooks **rely on a stable call order on every render of the same component**. This works well in practice because if you follow the rule above ("only call Hooks at the top level"), Hooks will always be called in the same order. Additionally, a [linter plugin](https://www.npmjs.com/package/eslint-plugin-react-hooks) catches most mistakes. +在内部,React 为每个组件保存了一个成对 state 数组。它还维护当前对索引,在渲染之前将其设置为“0”。每次调用 useState 时,React 都会为您提供下一个状态对并增加索引。您可以在 [React Hooks: Not Magic, Just Arrays](https://medium.com/@ryardley/react-hooks-not-magic-just-arrays-cd4f1857236e) 中阅读有关此机制的更多信息。 Internally, React holds an array of state pairs for every component. It also maintains the current pair index, which is set to `0` before rendering. Each time you call `useState`, React gives you the next state pair and increments the index. You can read more about this mechanism in [React Hooks: Not Magic, Just Arrays](https://medium.com/@ryardley/react-hooks-not-magic-just-arrays-cd4f1857236e). +这个例子**不使用 React**,但它让你了解 `useState` 在内部是如何工作的: This example **doesn't use React** but it gives you an idea of how `useState` works internally: @@ -718,14 +765,17 @@ button { display: block; margin-bottom: 10px; } +你不必理解它就可以使用 React,但你可能会发现这是一个有用的心智模型。 You don't have to understand it to use React, but you might find this a helpful mental model. ## State is isolated and private +State 是屏幕上组件实例内部的状态。换句话说,**如果你渲染同一个组件两次,每个副本都会有完全隔离的 state!**改变其中一个不会影响另一个。 State is local to a component instance on the screen. In other words, **if you render the same component twice, each copy will have completely isolated state!** Changing one of them will not affect the other. +在这个例子中,之前的 `Gallery` 组件被渲染了两次,其逻辑没有改变。尝试单击每个画廊内的按钮。请注意,它们的 state 是独立的: In this example, the `Gallery` component from earlier is rendered twice with no changes to its logic. Try clicking the buttons inside each of the galleries. Notice that their state is independent: @@ -885,14 +935,24 @@ button { +这就是 state 与您可能在模块顶部声明的常规变量不同的原因。 State 与特定的函数调用或代码中的某个位置无关,但它是屏幕上特定位置的“本地”。你渲染了两个 `` 组件,所以它们的 state 是分开存储的。 This is what makes state different from regular variables that you might declare at the top of your module. State is not tied to a particular function call or a place in the code, but it's "local" to the specific place on the screen. You rendered two `` components, so their state is stored separately. +还要注意 `Page` 组件如何“不知道”关于 `Gallery` state 的任何信息,甚至不知道它是否有任何 state。与 props 不同,**state 对于声明它的组件来说是完全私有的**。父组件无法更改它。这使您可以向任何组件添加状态或将其删除,而不会影响其余组件。 Also notice how the `Page` component doesn't "know" anything about the `Gallery` state or even whether it has any. Unlike props, **state is fully private to the component declaring it**. The parent component can't change it. This lets you add state to any component or remove it without impacting the rest of the components. +如果您希望两个画廊保持其 states 同步怎么办?在 React 中执行此操作的正确方法是从子组件中*删除* state 并将其添加到它们最近的共享父组件中。接下来的几页将专注于组织单个组件的状态,但我们将在 [组件间共享状态](/learn/sharing-state-between-components) 中回到这个主题。 What if you wanted both galleries to keep their states in sync? The right way to do it in React is to *remove* state from child components and add it to their closest shared parent. The next few pages will focus on organizing state of a single component, but we will return to this topic in [Sharing State Between Components](/learn/sharing-state-between-components). +* 当组件需要在渲染之间“记住”一些信息时使用状态变量。 +* 状态变量是通过调用`useState` Hook 来声明的。 +* Hooks 是以 `use` 开头的特殊函数。它们让你“连接”到像状态这样的 React 特性。 +* Hooks 可能会让你想起导入:它们需要被无条件调用。调用 Hooks,包括 `useState`,仅在组件或另一个 Hook 的顶层有效。 +* `useState` Hook 返回一对值:当前状态和更新它的函数。 +* 您可以拥有多个状态变量。在内部,React 按顺序匹配它们。 +* 状态是组件私有的。如果你在两个地方渲染它,每个副本都有自己的状态。 * Use a state variable when a component needs to "remember" some information between renders. * State variables are declared by calling the `useState` Hook. * Hooks are special functions that start with `use`. They let you "hook into" React features like state. From 875b72f84a044b13da6af6f7e6a9f79c0f43b6c2 Mon Sep 17 00:00:00 2001 From: 7ooz Date: Sun, 7 Nov 2021 23:02:28 +0800 Subject: [PATCH 2/8] docs(cn): state-a-components-memory --- .../pages/learn/state-a-components-memory.md | 150 +++++++----------- 1 file changed, 60 insertions(+), 90 deletions(-) diff --git a/beta/src/pages/learn/state-a-components-memory.md b/beta/src/pages/learn/state-a-components-memory.md index 174cb4c86a..d0f0bcd7e8 100644 --- a/beta/src/pages/learn/state-a-components-memory.md +++ b/beta/src/pages/learn/state-a-components-memory.md @@ -1,13 +1,12 @@ --- -title: "State: A Component's Memory" +title: "State: 组件的记忆" translators: - 7ooz --- -作为交互的结果,组件通常需要更改屏幕上的内容。输入表单应该更新输入字段,单击图片轮播上的“下一张”应该更改显示的图片,单击“购买”应该将商品放入购物车。组件需要“记忆”信息:当前输入值、当前图片、购物车。在 React 中,这种组件特有的内存称为 **state**。 -Components often need to change what's on the screen as a result of an interaction. Typing into the form should update the input field, clicking "next" on an image carousel should change which image is displayed, clicking "buy" should put a product in the shopping cart. Components need to "remember" things: the current input value, the current image, the shopping cart. In React, this kind of component-specific memory is called **state**. +组件通常需要根据交互更改屏幕上显示的内容。输入表单应该更新输入字段,单击图片轮播上的“下一个”应该更改显示的图片,单击“购买”应该将商品放入购物车。组件需要“记住”某些东西:当前输入值、当前图片、购物车。在 React 中,这种组件特有的记忆被称为 **state**。 @@ -16,18 +15,14 @@ Components often need to change what's on the screen as a result of an interacti * 如何使用 [`useState`](/reference/usestate) Hook 添加 state 变量 * `useState` Hook 返回哪一对值 * 如何添加多个 state 变量 -* 为什么 state 被称作局部的 -* How to add a state variable with the [`useState`](/reference/usestate) Hook -* What pair of values the `useState` Hook returns -* How to add more than one state variable +* 为什么 state 被称作是局部的 * Why state is called local ## When a regular variable isn’t enough -以下是一个渲染雕塑图片的组件。单击“下一步”按钮应该将 `index` 更改为 `1`,再次点击更改为 `2`,以此类推显示下一个雕塑。但是,这**行不通**(你可以尝试一下!): -Here's a component that renders a sculpture image. Clicking the "Next" button should show the next sculpture by changing the `index` to `1`, then `2`, and so on. However, this **won't work** (you can try it!): +以下是一个渲染雕塑图片的组件。点击“下一个”按钮应该显示下一个雕塑并将 `index` 更改为 `1`,再次点击又更改为 `2`,以此类推。但这个组件现在**不起作用**(你可以试一试!): @@ -159,29 +154,22 @@ button { -`handleClick()` 事件处理函数正在更新局部变量 `index`。但是有两件事阻止了这种变化是可见的: +`handleClick()` 事件处理函数正在更新局部变量 `index`。但是有两件事阻止了我们看到变化: The `handleClick()` event handler is updating a local variable, `index`. But two things prevent that change from being visible: -1. **局部变量不会在多次渲染间保存。** 当 React 第二次渲染这个组件时,它会从头开始渲染——不考虑对局部变量的任何更改。 +1. **局部变量无法在多次渲染中持久保存。** 当 React 第二次渲染这个组件时,它会从头开始渲染——不考虑对局部变量的任何更改。 2. **对局部变量的更改不会触发渲染。** React 没有意识到它需要使用新数据再次渲染组件。 -1. **Local variables don't persist between renders.** When React renders this component a second time, it renders it from scratch—it doesn't consider any changes to the local variables. -2. **Changes to local variables won't trigger renders.** React doesn't realize it needs to render the component again with the new data. 要使用新数据更新组件,需要做两件事: -To update a component with new data, two things need to happen: 1. **保留**渲染之间的数据。 2. **触发** React 使用新数据渲染组件(重新渲染)。 -1. **Retain** the data between renders. -2. **Trigger** React to render the component with new data (re-rendering). [`useState`](/reference/usestate) Hook 提供了这两个功能: -The [`useState`](/reference/usestate) Hook provides those two things: 1. **State 变量** 用于保留渲染之间的数据。 2. **State setter 函数** 更新变量并触发 React 再次渲染组件。 1. A **state variable** to retain the data between renders. -2. A **state setter function** to update the variable and trigger React to render the component again. ## Adding a state variable @@ -193,28 +181,23 @@ import { useState } from 'react'; ``` 然后,替换掉这一行: -Then, replace this line: ```js let index = 0; ``` 修改为 -with ```js const [index, setIndex] = useState(0); ``` -`index` 是一个 state 变量,`setIndex` 是 setter 函数。 -`index` is a state variable and `setIndex` is the setter function. +`index` 是一个 state 变量,`setIndex` 是对应的 setter 函数。 > 这里的 `[` 和 `]` 语法称为[数组解构](/learn/a-javascript-refresher#array-destructuring),它允许你从数组中读取值。 `useState` 返回的数组总是正好有两个项。 -> The `[` and `]` syntax here is called [array destructuring](/learn/a-javascript-refresher#array-destructuring) and it lets you read values from an array. The array returned by `useState` always has exactly two items. -以下展示了它们在 `handleClick()` 中是如何协同工作的: -This is how they work together in `handleClick()`: +以下展示了它们在 `handleClick()` 中是如何共同起作用的: ```js function handleClick() { @@ -222,8 +205,7 @@ function handleClick() { } ``` -现在点击“下一步”按钮切换当前雕塑: -Now clicking the "Next" button switches the current sculpture: +现在点击“下一个”按钮切换当前雕塑: @@ -359,66 +341,55 @@ button { ### Meet your first Hook 在 React 中,`useState` 以及任何其他以“`use`”开头的函数都被称为 **Hook**。 -In React, `useState`, as well as any other function starting with "`use`," is called a **Hook**. -Hooks 是特殊的函数,只有在 React [渲染](/learn/render-and-commit#step-1-trigger-a-render) 时才可用(我们将在下一节详细介绍)。它们让你“hook into”到不同的 React 特性。 +Hooks 是特殊的函数,只有在 React [渲染](/learn/render-and-commit#step-1-trigger-a-render)时才可用(我们将在下一节详细介绍)。它们能让你“hook”到不同的 React 特性中去。 Hooks are special functions that are only available while React is [rendering](/learn/render-and-commit#step-1-trigger-a-render) (which we'll get into in more detail on the next page). They let you "hook into" different React features. -State 只是这些功能之一,但你稍后会遇到其他 Hook。 -State is just one of those features, but you will meet the other Hooks later. +State 只是这些特性中的一个,你之后还会遇到其他 Hooks。 -**Hooks——以`use`开头的函数——只能在组件或[自定义 Hooks](/learn/reusing-logic-with-custom-hooks)的顶层调用。**你不能调用条件、循环或其他嵌套函数内的 Hooks。Hooks 是函数,但将它们视为关于组件需求的无条件声明会很有帮助。你在组件顶部“使用”React 功能类似于在文件顶部“导入”模块的方式。 -**Hooks—functions starting with `use`—can only be called at the top level of your components or [your own Hooks](/learn/reusing-logic-with-custom-hooks).** You can't call Hooks inside conditions, loops, or other nested functions. Hooks are functions, but it's helpful to think of them as unconditional declarations about your component's needs. You "use" React features at the top of your component similar to how you "import" modules at the top of your file. +**Hooks——以`use`开头的函数——只能在组件或[自定义 Hooks](/learn/reusing-logic-with-custom-hooks)的最顶层调用。**你不能调用条件表达式、循环或其他嵌套函数内的 Hooks。Hooks 是函数,但将它们视为关于组件需求的无条件声明会很有帮助。你在组件顶部“使用”React 功能类似于在文件顶部“导入”模块的方式。 +You can't call Hooks inside conditions, loops, or other nested functions. Hooks are functions, but it's helpful to think of them as unconditional declarations about your component's needs. You "use" React features at the top of your component similar to how you "import" modules at the top of your file. ### Anatomy of `useState` 当你调用 [`useState`](/reference/usestate) 时,你是在告诉 React 你想让这个组件记住一些东西: -When you call [`useState`](/reference/usestate), you are telling React that you want this component to remember something: ```js const [index, setIndex] = useState(0); ``` 在这个例子里,你希望 React 记住 `index`。 -In this case, you want React to remember `index`. -> 惯例是将这对命名为 `const [thing, setThing]`。你可以将其命名为任何你喜欢的名称,但约定俗成能使跨项目的事情更容易理解。 -> The convention is to name this pair like `const [thing, setThing]`. You could name it anything you like, but conventions make things easier to understand across projects. +> 惯例是将这对值命名为 `const [thing, setThing]`。你可以将其命名为任何你喜欢的名称,但约定俗成能使跨项目的事情更容易理解。 +You could name it anything you like, but conventions make things easier to understand across projects. -`useState` 的唯一参数是状态变量的**初始值**。在这个例子中,`index` 的初始值被设置为 `useState(0)` 的 `0`。 +`useState` 的唯一参数是 state 变量的**初始值**。在这个例子中,`index` 的初始值被`useState(0)`设置为 `0`。 The only argument to `useState` is the **initial value** of your state variable. In this example, the `index`'s initial value is set to `0` with `useState(0)`. 每次你的组件渲染时,`useState` 都会给你一个包含两个值的数组: -Every time your component renders, `useState` gives you an array containing two values: 1. **state 变量** (`index`) 与你存储的值。 -2. **state setter 函数** (`setIndex`) 可以更新状态变量并触发 React 重新渲染组件。 -1. The **state variable** (`index`) with the value you stored. -2. The **state setter function** (`setIndex`) which can update the state variable and trigger React to render the component again. +2. **state setter 函数** (`setIndex`) 可以更新 state 变量并触发 React 重新渲染组件。 -这是实际发生的情况: +以下是实际发生的情况: Here's how that happens in action: ```js const [index, setIndex] = useState(0); ``` -1. **组件第一次渲染。** 因为你将 `0` 作为 `index` 的初始值传递给 `useState`,它将返回 `[0, setIndex]`。 React 记得 `0` 是最新的状态值。 -2. **你更新了状态。**当用户点击按钮时,它会调用`setIndex(index + 1)`。 `index` 是 `0`,所以它是 `setIndex(1)`。这告诉 React 现在记住 `index` 是 `1` 并触发另一个渲染。 -3. **组件第二次渲染。** React 仍然看到 `useState(0)`,但是因为 React *记住* 你将 `index` 设置为 `1`,它返回 `[1, setIndex]`。 +1. **组件进行第一次渲染。** 因为你将 `0` 作为 `index` 的初始值传递给 `useState`,它将返回 `[0, setIndex]`。 React 记住 `0` 是最新的 state 值。 +2. **你更新了 state。**当用户点击按钮时,它会调用 `setIndex(index + 1)`。 `index` 是 `0`,所以它是 `setIndex(1)`。这告诉 React 现在记住 `index` 是 `1` 并触发另一个渲染。 +3. **组件进行第二次渲染。** React 仍然看到 `useState(0)`,但是因为 React *记住* 了你将 `index` 设置为了 `1`,它将返回 `[1, setIndex]`。 4. 以此类推! -1. **Your component renders the first time.** Because you passed `0` to `useState` as the initial value for `index`, it will return `[0, setIndex]`. React remembers `0` is the latest state value. -2. **You update the state.** When a user clicks the button, it calls `setIndex(index + 1)`. `index` is `0`, so it's `setIndex(1)`. This tells React to remember `index` is `1` now and triggers another render. -3. **Your component's second render.** React still sees `useState(0)`, but because React *remembers* that you set `index` to `1`, it returns `[1, setIndex]` instead. -4. And so on! ## Giving a component multiple state variables -您可以在一个组件中拥有任意多种类型的状态变量。该组件有两个状态变量,一个数字 `index` 和一个布尔值 `showMore`,当您单击“显示详细信息”时会切换该变量: +你可以在一个组件中拥有任意多种类型的 state 变量。该组件有两个 state 变量,一个数字 `index` 和一个点击 “Show Details” 会切换的布尔值 `showMore`: You can have as many state variables of as many types as you like in one component. This component has two state variables, a number `index` and a boolean `showMore` that's toggled when you click "Show details": @@ -558,22 +529,18 @@ button { -如果它们的 state 不相关,那么拥有多个 state 变量是一个好主意,例如本例中的 `index` 和 `showMore`。但是,如果您发现经常一起更改两个 state 变量,则最好将它们合并为一个。例如,如果您有一个包含多个字段的表单,那么拥有一个保存对象的单个 state 变量比每个字段的 state 变量更方便。 [Choosing the State Structure](/learn/choosing-the-state-structure)在这方面有更多提示。 -It is a good idea to have multiple state variables if their state is unrelated, like `index` and `showMore` in this example. But if you find that you often change two state variables together, it might be better to combine them into a single one. For example, if you have a form with many fields, it's more convenient to have a single state variable that holds an object than state variable per field. [Choosing the State Structure](/learn/choosing-the-state-structure) has more tips on this. +如果它们不相关,那么存在多个 state 变量是一个好主意,例如本例中的 `index` 和 `showMore`。但是,如果你发现经常同时更改两个 state 变量,那么最好将它们合并为一个。例如,如果你有一个包含多个字段的表单,那么拥有一个值为对象的 state 变量比每个字段对应一个 state 变量更方便。 [选择 state 结构](/learn/choosing-the-state-structure)在这方面有更多提示。 -您可能已经注意到,`useState` 调用没有收到关于它引用的*哪个* state 变量的任何信息。没有传递给`useState` 的“标识符”,那么它如何知道要返回哪个 state 变量呢?它是否依赖于解析函数之类的魔法?答案是否。 -You might have noticed that the `useState` call does not receive any information about *which* state variable it refers to. There is no "identifier" that is passed to `useState`, so how does it know which of the state variables to return? Does it rely on some magic like parsing your functions? The answer is no. +你可能已经注意到,`useState` 在调用时没有任何关于它引用的是*哪个* state 变量的信息。没有传递给 `useState` 的“标识符”,它是如何知道要返回哪个 state 变量呢?它是否依赖于解析函数之类的魔法?答案是否定的。 -相反,为了启用其简洁的语法,Hooks **依赖于同一组件的每次渲染**的稳定调用顺序。这在实践中很有效,因为如果你遵循上面的规则(“只在顶层调用 Hooks”),Hooks 将始终以相同的顺序被调用。此外,[linter 插件](https://www.npmjs.com/package/eslint-plugin-react-hooks) 可以捕获大多数错误。 -Instead, to enable their concise syntax, Hooks **rely on a stable call order on every render of the same component**. This works well in practice because if you follow the rule above ("only call Hooks at the top level"), Hooks will always be called in the same order. Additionally, a [linter plugin](https://www.npmjs.com/package/eslint-plugin-react-hooks) catches most mistakes. +相反,为了使语法更简洁,**在同一组件的每次渲染中,Hooks 都依托于一个稳定的调用顺序**。这在实践中很有效,因为如果你遵循上面的规则(“只在顶层调用 Hooks”),Hooks 将始终以相同的顺序被调用。此外,[linter 插件](https://www.npmjs.com/package/eslint-plugin-react-hooks)也可以捕获大多数错误。 -在内部,React 为每个组件保存了一个成对 state 数组。它还维护当前对索引,在渲染之前将其设置为“0”。每次调用 useState 时,React 都会为您提供下一个状态对并增加索引。您可以在 [React Hooks: Not Magic, Just Arrays](https://medium.com/@ryardley/react-hooks-not-magic-just-arrays-cd4f1857236e) 中阅读有关此机制的更多信息。 -Internally, React holds an array of state pairs for every component. It also maintains the current pair index, which is set to `0` before rendering. Each time you call `useState`, React gives you the next state pair and increments the index. You can read more about this mechanism in [React Hooks: Not Magic, Just Arrays](https://medium.com/@ryardley/react-hooks-not-magic-just-arrays-cd4f1857236e). +在内部,React 为每个组件保存了一个包含 state 对的数组。它还维护当前对的索引,在渲染之前将其设置为“0”。每次调用 useState 时,React 都会为你提供下一个 state 对并增加索引。你可以在文章 [React Hooks: 不是魔法,只是数组](https://medium.com/@ryardley/react-hooks-not-magic-just-arrays-cd4f1857236e)中阅读有关此机制的更多信息。 +Internally, React holds an array of state pairs for every component. It also maintains the current pair index, which is set to `0` before rendering. Each time you call `useState`, React gives you the next state pair and increments the index. 这个例子**不使用 React**,但它让你了解 `useState` 在内部是如何工作的: -This example **doesn't use React** but it gives you an idea of how `useState` works internally: @@ -766,17 +733,14 @@ button { display: block; margin-bottom: 10px; } 你不必理解它就可以使用 React,但你可能会发现这是一个有用的心智模型。 -You don't have to understand it to use React, but you might find this a helpful mental model. ## State is isolated and private State 是屏幕上组件实例内部的状态。换句话说,**如果你渲染同一个组件两次,每个副本都会有完全隔离的 state!**改变其中一个不会影响另一个。 -State is local to a component instance on the screen. In other words, **if you render the same component twice, each copy will have completely isolated state!** Changing one of them will not affect the other. -在这个例子中,之前的 `Gallery` 组件被渲染了两次,其逻辑没有改变。尝试单击每个画廊内的按钮。请注意,它们的 state 是独立的: -In this example, the `Gallery` component from earlier is rendered twice with no changes to its logic. Try clicking the buttons inside each of the galleries. Notice that their state is independent: +在这个例子中,之前的 `Gallery` 组件以同样的逻辑被渲染了两次。试着点击每个画廊内的按钮。你会注意到它们的 state 是相互独立的: @@ -935,31 +899,24 @@ button { -这就是 state 与您可能在模块顶部声明的常规变量不同的原因。 State 与特定的函数调用或代码中的某个位置无关,但它是屏幕上特定位置的“本地”。你渲染了两个 `` 组件,所以它们的 state 是分开存储的。 -This is what makes state different from regular variables that you might declare at the top of your module. State is not tied to a particular function call or a place in the code, but it's "local" to the specific place on the screen. You rendered two `` components, so their state is stored separately. +这就是 state 与你可能在模块顶部声明的常规变量不同的原因。 State 与特定的函数调用或代码中的位置无关,但它只作用于屏幕上的某块特定区域。你渲染了两个 `` 组件,所以它们的 state 是分开存储的。 +but it's "local" to the specific place on the screen. -还要注意 `Page` 组件如何“不知道”关于 `Gallery` state 的任何信息,甚至不知道它是否有任何 state。与 props 不同,**state 对于声明它的组件来说是完全私有的**。父组件无法更改它。这使您可以向任何组件添加状态或将其删除,而不会影响其余组件。 -Also notice how the `Page` component doesn't "know" anything about the `Gallery` state or even whether it has any. Unlike props, **state is fully private to the component declaring it**. The parent component can't change it. This lets you add state to any component or remove it without impacting the rest of the components. +还要注意 `Page` 组件“不知道”关于 `Gallery` state 的任何信息,甚至不知道它是否有任何 state。与 props 不同,**state 完全私有于声明它的组件**。父组件无法更改它。这使你可以向任何组件添加或删除 state,而不会影响其余组件。 -如果您希望两个画廊保持其 states 同步怎么办?在 React 中执行此操作的正确方法是从子组件中*删除* state 并将其添加到它们最近的共享父组件中。接下来的几页将专注于组织单个组件的状态,但我们将在 [组件间共享状态](/learn/sharing-state-between-components) 中回到这个主题。 -What if you wanted both galleries to keep their states in sync? The right way to do it in React is to *remove* state from child components and add it to their closest shared parent. The next few pages will focus on organizing state of a single component, but we will return to this topic in [Sharing State Between Components](/learn/sharing-state-between-components). +如果你希望两个画廊保持其 states 同步怎么办?在 React 中执行此操作的正确方法是从子组件中*删除* state 并将其添加到离它们最近的共享父组件中。接下来的几节将专注于组织单个组件的 state,但我们将在[组件间共享 state](/learn/sharing-state-between-components)中回到这个主题。 -* 当组件需要在渲染之间“记住”一些信息时使用状态变量。 -* 状态变量是通过调用`useState` Hook 来声明的。 -* Hooks 是以 `use` 开头的特殊函数。它们让你“连接”到像状态这样的 React 特性。 -* Hooks 可能会让你想起导入:它们需要被无条件调用。调用 Hooks,包括 `useState`,仅在组件或另一个 Hook 的顶层有效。 -* `useState` Hook 返回一对值:当前状态和更新它的函数。 -* 您可以拥有多个状态变量。在内部,React 按顺序匹配它们。 -* 状态是组件私有的。如果你在两个地方渲染它,每个副本都有自己的状态。 -* Use a state variable when a component needs to "remember" some information between renders. -* State variables are declared by calling the `useState` Hook. +* 当一个组件需要在多次渲染间“记住”某些信息时使用 state 变量。 +* State 变量是通过调用 `useState` Hook 来声明的。 +* Hooks 是以 `use` 开头的特殊函数。它们让你“连接”到像 state 这样的 React 特性。 +* Hooks 可能会让你想起 imports:它们需要被无条件调用。调用 Hooks,包括 `useState`,仅在组件或另一个 Hook 的顶层有效。 +* `useState` Hook 返回一对值:当前 state 和更新它的函数。 +* 你可以拥有多个 state 变量。在内部,React 按顺序匹配它们。 +* State 是组件私有的。如果你在两个地方渲染它,则每个副本都有独属于自己的 state。 * Hooks are special functions that start with `use`. They let you "hook into" React features like state. * Hooks might remind you of imports: they need to be called unconditionally. Calling Hooks, including `useState`, is only valid at the top level of a component or another Hook. -* The `useState` Hook returns a pair of values: the current state and the function to update it. -* You can have more than one state variable. Internally, React matches them up by their order. -* State is private to the component. If you render it in two places, each copy gets its own state. @@ -969,8 +926,10 @@ What if you wanted both galleries to keep their states in sync? The right way to ### Complete the gallery +当你在最后一个雕塑上按“下一步”时,代码会崩溃。修复逻辑以防止崩溃。你可以尝试在事件处理函数中添加额外的逻辑,或在无法执行操作时禁用掉按钮。 When you press "Next" on the last sculpture, the code crashes. Fix the logic to prevent the crash. You may do this by adding extra logic to event handler or by disabling the button when the action is not possible. +修复崩溃后,添加一个显示上一个雕塑的“previous”按钮。它也不应该在第一个雕塑里发生崩溃。 After fixing the crash, add a "Previous" button that shows the previous sculpture. It shouldn't crash on the first sculpture. @@ -1113,6 +1072,7 @@ img { width: 120px; height: 120px; } +这在两个事件处理函数中添加了一个保护条件,并在需要时禁用按钮: This adds a guarding condition inside both event handlers and disables the buttons when needed: @@ -1273,13 +1233,14 @@ img { width: 120px; height: 120px; } +注意 `hasPrev` 和 `hasNext` 是如何*同时* 作用于返回的 JSX 和事件处理函数中的!这种简便模式之所以有效,是因为事件处理函数["闭包"](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures)了渲染时声明的任何变量。 Notice how `hasPrev` and `hasNext` are used *both* for the returned JSX and inside the event handlers! This handy pattern works because event handler functions ["close over"](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures) any variables declared while rendering. ### Fix stuck form inputs -When you type into the input fields, nothing appears. It's like the input values are "stuck" with empty strings. The `value` of the first `` is set to always match the `firstName` variable, and the `value` for the second `` is set to always match the `lastName` variable. This is correct. Both inputs have `onChange` event handlers, which try to update the variables based on the latest user input (`e.target.value`). However, the variables don't seem to "remember" their values between re-renders. Fix this by using state variables instead. +当你输入字段时,什么也没有出现。这就像输入值被空字符串给“卡住”了。第一个 `` 的 `value` 设置为始终匹配 `firstName` 变量,第二个 `` 的 `value` 设置为始终匹配 `lastName` 变量。这是对的。两个输入框都有 `onChange` 事件处理函数,它尝试根据最新的用户输入(`e.target.value`)更新变量。但是,变量似乎并没有在重新渲染时“记住”它们的值。通过使用 state 变量来解决此问题。 @@ -1328,7 +1289,7 @@ h1 { margin-top: 10px; } -First, import `useState` from React. Then replace `firstName` and `lastName` with state variables declared by calling `useState`. Finally, replace every `firstName = ...` assignment with `setFirstName(...)`, and do the same for `lastName`. Don't forget to update `handleReset` too so that the reset button works. +首先,从 React 导入 `useState`。然后用 `useState` 声明的 state 变量替换 `firstName` 和 `lastName`。最后,用 `setFirstName(...)` 替换每个 `firstName = ...` 赋值,并对 `lastName` 做同样的事情。不要忘记更新 `handleReset`,以便重置按钮。 @@ -1381,10 +1342,12 @@ h1 { margin-top: 10px; } ### Fix a crash +这是一个小表单,用于让用户留下一些反馈。当反馈被提交时,它应该显示一条感谢信息。但是,现在它会发生崩溃并显示错误消息“渲染的 hooks 比预期的少”。你能发现错误并修复它吗? Here is a small form that is supposed to let the user leave some feedback. When the feedback is submitted, it's supposed to display a thank-you message. However, it crashes with an error message saying "Rendered fewer hooks than expected". Can you spot the mistake and fix it? +对于 Hooks 在什么地方被调用,有任何限制吗?这个组件是否违反了任何规则? Are there any limitations on _where_ Hooks may be called? Does this component break any rules? @@ -1423,6 +1386,7 @@ export default function FeedbackForm() { +Hooks 只能在组件函数的顶层调用。这里,第一个 `isSent` 定义遵循这个规则,但是 `message` 定义嵌套在一个条件语句中。将其移出条件语句以解决问题: Hooks can only be called at the top level of the component function. Here, the first `isSent` definition follows this rule, but the `message` definition is nested in a condition. Move it out of the condition to fix the issue: @@ -1458,9 +1422,11 @@ export default function FeedbackForm() { +请记住,必须在条件语句外并且始终以相同的顺序调用 Hook! Remember, Hooks must be called unconditionally and always in the same order! -You could also remove the unnecessary `else` branch to reduce the nesting. However, it's still important that all calls to Hooks happen *before* the first `return`. + +你还可以删除不必要的`else` 分支以减少嵌套。但要保证对 Hooks 的所有调用都发生在*第一个 `return` 前,这很重要。 @@ -1495,19 +1461,22 @@ export default function FeedbackForm() { +尝试移动第二个 `useState` 调用到 `if` 条件之后,并注意这如何再次破坏了它。 Try moving the second `useState` call after the `if` condition and notice how this breaks it again. -In general, these types of mistakes are caught by the [`eslint-plugin-react-hooks`](https://www.npmjs.com/package/eslint-plugin-react-hooks) linter rule. If you don't see an error when you try the faulty code locally, you need to set it up in your build tooling configuration. +通常,以上类型的错误都会由 [`eslint-plugin-react-hooks`](https://www.npmjs.com/package/eslint-plugin-react-hooks) linter 规则捕获。如果在本地调试错误代码时没有看到错误,则需要在构建工具的配置文件中进行设置。 ### Remove unnecessary state -When the button is clicked, this example should ask for the user's name and then display an alert gretting them. You tried to use state to keep the name, but for some reason it always shows "Hello, !". +当按钮被点击时,这个例子应该询问用户的名字,然后显示一个 alert 欢迎他们。你尝试使用 state 来保存名字,但由于某种原因,它始终显示“Hello, !”。 + -To fix this code, remove the unnecessary state variable. (We will discuss about [why this didn't work](/learn/troubleshooting-state-updates#setting-state-does-not-update-variables) later.) +要修复此代码,请删除不必要的 state 变量。(我们将在稍后讨论 [为什么以上代码不起作用](/learn/troubleshooting-state-updates#setting-state-does-not-update-variables)。) +(We will discuss about [why this didn't work](/learn/troubleshooting-state-updates#setting-state-does-not-update-variables) later.) -Can you explain why this state variable was unnecessary? +你能解释为什么这个 state 变量是不必要的吗? @@ -1534,6 +1503,7 @@ export default function FeedbackForm() { +以下是一个使用声明于需要她的函数中的一般 `name` 变量的固定版本: Here is a fixed version that uses a regular `name` variable declared in the function that needs it: @@ -1557,7 +1527,7 @@ export default function FeedbackForm() { -A state variable is only necessary to keep information between re-renders of a component. Within a single event handler, a regular variable will do fine. Don't introduce state variables when a regular variable works well. +State 变量仅用于在组件重渲染时保存信息。在单个事件处理函数中,一般变量就足够了。当一般变量运行良好时,不要引入 state 变量。 From aaa88b201e06939aa18552ce14d87611c7819443 Mon Sep 17 00:00:00 2001 From: zhaozhiwei Date: Mon, 8 Nov 2021 19:00:44 +0800 Subject: [PATCH 3/8] docs(cn): state-a-components-memory --- .../pages/learn/state-a-components-memory.md | 105 +++++++----------- 1 file changed, 40 insertions(+), 65 deletions(-) diff --git a/beta/src/pages/learn/state-a-components-memory.md b/beta/src/pages/learn/state-a-components-memory.md index d0f0bcd7e8..dd1079c3cc 100644 --- a/beta/src/pages/learn/state-a-components-memory.md +++ b/beta/src/pages/learn/state-a-components-memory.md @@ -1,12 +1,12 @@ --- -title: "State: 组件的记忆" +title: "State:组件的记忆" translators: - 7ooz --- -组件通常需要根据交互更改屏幕上显示的内容。输入表单应该更新输入字段,单击图片轮播上的“下一个”应该更改显示的图片,单击“购买”应该将商品放入购物车。组件需要“记住”某些东西:当前输入值、当前图片、购物车。在 React 中,这种组件特有的记忆被称为 **state**。 +组件通常需要根据交互更改屏幕上显示的内容。输入表单应该更新输入字段,单击轮播图上的“下一个”应该更改显示的图片,单击“购买”应该将商品放入购物车。组件需要“记住”某些东西:当前输入值、当前图片、购物车。在 React 中,这种组件特有的记忆被称为 **state**。 @@ -16,13 +16,12 @@ translators: * `useState` Hook 返回哪一对值 * 如何添加多个 state 变量 * 为什么 state 被称作是局部的 -* Why state is called local -## When a regular variable isn’t enough +## 当一般变量不够时 {#when-a-regular-variable-isnt-enough} -以下是一个渲染雕塑图片的组件。点击“下一个”按钮应该显示下一个雕塑并将 `index` 更改为 `1`,再次点击又更改为 `2`,以此类推。但这个组件现在**不起作用**(你可以试一试!): +以下是一个渲染雕塑图片的组件。点击“Next”按钮应该显示下一个雕塑并将 `index` 更改为 `1`,再次点击又更改为 `2`,以此类推。但这个组件现在**不起作用**(你可以试一试!): @@ -154,11 +153,10 @@ button { -`handleClick()` 事件处理函数正在更新局部变量 `index`。但是有两件事阻止了我们看到变化: -The `handleClick()` event handler is updating a local variable, `index`. But two things prevent that change from being visible: +`handleClick()` 事件处理函数正在更新局部变量 `index`。但存在两个原因使得变化不可见: -1. **局部变量无法在多次渲染中持久保存。** 当 React 第二次渲染这个组件时,它会从头开始渲染——不考虑对局部变量的任何更改。 -2. **对局部变量的更改不会触发渲染。** React 没有意识到它需要使用新数据再次渲染组件。 +1. **局部变量无法在多次渲染中持久保存。** 当 React 第二次渲染这个组件时,它会从头开始渲染——不考虑之前对局部变量的任何更改。 +2. **更改局部变量不会触发渲染。** React 没有意识到它需要使用新数据再次渲染组件。 要使用新数据更新组件,需要做两件事: @@ -167,26 +165,24 @@ The `handleClick()` event handler is updating a local variable, `index`. But two [`useState`](/reference/usestate) Hook 提供了这两个功能: -1. **State 变量** 用于保留渲染之间的数据。 +1. **State 变量** 用于保存渲染间的数据。 2. **State setter 函数** 更新变量并触发 React 再次渲染组件。 -1. A **state variable** to retain the data between renders. -## Adding a state variable +## 添加一个 state 变量 {#adding-a-state-variable} -要添加 state 变量,请从文件顶部的 React 导入 `useState`: -To add a state variable, import `useState` from React at the top of the file: +要添加 state 变量,先从文件顶部的 React 中导入 `useState`: ```js import { useState } from 'react'; ``` -然后,替换掉这一行: +然后,替换这一行: ```js let index = 0; ``` -修改为 +将其修改为 ```js const [index, setIndex] = useState(0); @@ -205,7 +201,7 @@ function handleClick() { } ``` -现在点击“下一个”按钮切换当前雕塑: +现在点击“Next”按钮切换当前雕塑: @@ -338,23 +334,21 @@ button { -### Meet your first Hook +### 遇见你的第一个 Hook {#meet-your-first-hook} 在 React 中,`useState` 以及任何其他以“`use`”开头的函数都被称为 **Hook**。 -Hooks 是特殊的函数,只有在 React [渲染](/learn/render-and-commit#step-1-trigger-a-render)时才可用(我们将在下一节详细介绍)。它们能让你“hook”到不同的 React 特性中去。 -Hooks are special functions that are only available while React is [rendering](/learn/render-and-commit#step-1-trigger-a-render) (which we'll get into in more detail on the next page). They let you "hook into" different React features. +Hooks 是特殊的函数,只在 React [渲染](/learn/render-and-commit#step-1-trigger-a-render)时有效(我们将在下一节详细介绍)。它们能让你“hook”到不同的 React 特性中去。 State 只是这些特性中的一个,你之后还会遇到其他 Hooks。 -**Hooks——以`use`开头的函数——只能在组件或[自定义 Hooks](/learn/reusing-logic-with-custom-hooks)的最顶层调用。**你不能调用条件表达式、循环或其他嵌套函数内的 Hooks。Hooks 是函数,但将它们视为关于组件需求的无条件声明会很有帮助。你在组件顶部“使用”React 功能类似于在文件顶部“导入”模块的方式。 -You can't call Hooks inside conditions, loops, or other nested functions. Hooks are functions, but it's helpful to think of them as unconditional declarations about your component's needs. You "use" React features at the top of your component similar to how you "import" modules at the top of your file. +**Hooks——以 `use` 开头的函数——只能在组件或[自定义 Hooks](/learn/reusing-logic-with-custom-hooks) 的最顶层调用。**你不能在条件语句、循环语句或其他嵌套函数内调用 Hooks。Hooks 是函数,但将它们视为关于组件需求的无条件声明会很有帮助。在组件顶部“use” React 特性,类似于在文件顶部“导入”模块。 -### Anatomy of `useState` +### 剖析 `useState` {#anatomy-of-usestate} 当你调用 [`useState`](/reference/usestate) 时,你是在告诉 React 你想让这个组件记住一些东西: @@ -364,11 +358,9 @@ const [index, setIndex] = useState(0); 在这个例子里,你希望 React 记住 `index`。 -> 惯例是将这对值命名为 `const [thing, setThing]`。你可以将其命名为任何你喜欢的名称,但约定俗成能使跨项目的事情更容易理解。 -You could name it anything you like, but conventions make things easier to understand across projects. +> 惯例是将这对返回值命名为 `const [thing, setThing]`。你也可以将其命名为任何你喜欢的名称,但遵照约定俗成能使跨项目合作更易理解。 `useState` 的唯一参数是 state 变量的**初始值**。在这个例子中,`index` 的初始值被`useState(0)`设置为 `0`。 -The only argument to `useState` is the **initial value** of your state variable. In this example, the `index`'s initial value is set to `0` with `useState(0)`. 每次你的组件渲染时,`useState` 都会给你一个包含两个值的数组: @@ -376,7 +368,6 @@ The only argument to `useState` is the **initial value** of your state variable. 2. **state setter 函数** (`setIndex`) 可以更新 state 变量并触发 React 重新渲染组件。 以下是实际发生的情况: -Here's how that happens in action: ```js const [index, setIndex] = useState(0); @@ -387,10 +378,9 @@ const [index, setIndex] = useState(0); 3. **组件进行第二次渲染。** React 仍然看到 `useState(0)`,但是因为 React *记住* 了你将 `index` 设置为了 `1`,它将返回 `[1, setIndex]`。 4. 以此类推! -## Giving a component multiple state variables +## 赋予一个组件多个 state 变量 {#giving-a-component-multiple-state-variables} -你可以在一个组件中拥有任意多种类型的 state 变量。该组件有两个 state 变量,一个数字 `index` 和一个点击 “Show Details” 会切换的布尔值 `showMore`: -You can have as many state variables of as many types as you like in one component. This component has two state variables, a number `index` and a boolean `showMore` that's toggled when you click "Show details": +你可以在一个组件中拥有任意多种类型的 state 变量。该组件有两个 state 变量,一个数字 `index` 和一个布尔值 `showMore`,点击 “Show Details” 会改变 `showMore` 的值: @@ -531,14 +521,13 @@ button { 如果它们不相关,那么存在多个 state 变量是一个好主意,例如本例中的 `index` 和 `showMore`。但是,如果你发现经常同时更改两个 state 变量,那么最好将它们合并为一个。例如,如果你有一个包含多个字段的表单,那么拥有一个值为对象的 state 变量比每个字段对应一个 state 变量更方便。 [选择 state 结构](/learn/choosing-the-state-structure)在这方面有更多提示。 - + 你可能已经注意到,`useState` 在调用时没有任何关于它引用的是*哪个* state 变量的信息。没有传递给 `useState` 的“标识符”,它是如何知道要返回哪个 state 变量呢?它是否依赖于解析函数之类的魔法?答案是否定的。 相反,为了使语法更简洁,**在同一组件的每次渲染中,Hooks 都依托于一个稳定的调用顺序**。这在实践中很有效,因为如果你遵循上面的规则(“只在顶层调用 Hooks”),Hooks 将始终以相同的顺序被调用。此外,[linter 插件](https://www.npmjs.com/package/eslint-plugin-react-hooks)也可以捕获大多数错误。 -在内部,React 为每个组件保存了一个包含 state 对的数组。它还维护当前对的索引,在渲染之前将其设置为“0”。每次调用 useState 时,React 都会为你提供下一个 state 对并增加索引。你可以在文章 [React Hooks: 不是魔法,只是数组](https://medium.com/@ryardley/react-hooks-not-magic-just-arrays-cd4f1857236e)中阅读有关此机制的更多信息。 -Internally, React holds an array of state pairs for every component. It also maintains the current pair index, which is set to `0` before rendering. Each time you call `useState`, React gives you the next state pair and increments the index. +在内部,React 为每个组件保存了一个数组,其中每一项都是一个 state 对。它维护当前 state 对的索引值,在渲染之前将其设置为“0”。每次调用 useState 时,React 都会为你提供一个 state 对并增加索引值。你可以在文章 [React Hooks: not magic, just arrays](https://medium.com/@ryardley/react-hooks-not-magic-just-arrays-cd4f1857236e)中阅读有关此机制的更多信息。 这个例子**不使用 React**,但它让你了解 `useState` 在内部是如何工作的: @@ -736,7 +725,7 @@ button { display: block; margin-bottom: 10px; } -## State is isolated and private +## State 是独立且私有的 {#state-is-isolated-and-private} State 是屏幕上组件实例内部的状态。换句话说,**如果你渲染同一个组件两次,每个副本都会有完全隔离的 state!**改变其中一个不会影响另一个。 @@ -899,8 +888,7 @@ button { -这就是 state 与你可能在模块顶部声明的常规变量不同的原因。 State 与特定的函数调用或代码中的位置无关,但它只作用于屏幕上的某块特定区域。你渲染了两个 `` 组件,所以它们的 state 是分开存储的。 -but it's "local" to the specific place on the screen. +这就是 state 与声明在模块顶部的一般变量不同的原因。 State 与特定的函数调用或在代码中的位置无关,它的作用域“只限于”屏幕上的某块特定区域。你渲染了两个 `` 组件,所以它们的 state 是分开存储的。 还要注意 `Page` 组件“不知道”关于 `Gallery` state 的任何信息,甚至不知道它是否有任何 state。与 props 不同,**state 完全私有于声明它的组件**。父组件无法更改它。这使你可以向任何组件添加或删除 state,而不会影响其余组件。 @@ -910,13 +898,11 @@ but it's "local" to the specific place on the screen. * 当一个组件需要在多次渲染间“记住”某些信息时使用 state 变量。 * State 变量是通过调用 `useState` Hook 来声明的。 -* Hooks 是以 `use` 开头的特殊函数。它们让你“连接”到像 state 这样的 React 特性。 -* Hooks 可能会让你想起 imports:它们需要被无条件调用。调用 Hooks,包括 `useState`,仅在组件或另一个 Hook 的顶层有效。 +* Hooks 是以 `use` 开头的特殊函数。它们能让你“hook”到像 state 这样的 React 特性中。 +* Hooks 可能会让你想起 imports:它们需要被无条件调用。Hooks,包括 `useState`,仅在组件或另一个 Hook 的顶层被调用才有效。 * `useState` Hook 返回一对值:当前 state 和更新它的函数。 * 你可以拥有多个 state 变量。在内部,React 按顺序匹配它们。 * State 是组件私有的。如果你在两个地方渲染它,则每个副本都有独属于自己的 state。 -* Hooks are special functions that start with `use`. They let you "hook into" React features like state. -* Hooks might remind you of imports: they need to be called unconditionally. Calling Hooks, including `useState`, is only valid at the top level of a component or another Hook. @@ -924,13 +910,11 @@ but it's "local" to the specific place on the screen. -### Complete the gallery +### 完成画廊组件 -当你在最后一个雕塑上按“下一步”时,代码会崩溃。修复逻辑以防止崩溃。你可以尝试在事件处理函数中添加额外的逻辑,或在无法执行操作时禁用掉按钮。 -When you press "Next" on the last sculpture, the code crashes. Fix the logic to prevent the crash. You may do this by adding extra logic to event handler or by disabling the button when the action is not possible. +当你在最后一个雕塑上按“Next”时,代码会发生崩溃。请修复逻辑以防止此崩溃。你可以尝试在事件处理函数中添加额外的逻辑,或在操作无法执行时禁用掉按钮。 -修复崩溃后,添加一个显示上一个雕塑的“previous”按钮。它也不应该在第一个雕塑里发生崩溃。 -After fixing the crash, add a "Previous" button that shows the previous sculpture. It shouldn't crash on the first sculpture. +修复崩溃后,添加一个显示上一个雕塑的“Previous”按钮。同样地,确保它不在第一个雕塑里发生崩溃。 @@ -1072,8 +1056,7 @@ img { width: 120px; height: 120px; } -这在两个事件处理函数中添加了一个保护条件,并在需要时禁用按钮: -This adds a guarding condition inside both event handlers and disables the buttons when needed: +两个事件处理函数中均添加了一个保护条件,并在需要时禁用了按钮: @@ -1233,12 +1216,11 @@ img { width: 120px; height: 120px; } -注意 `hasPrev` 和 `hasNext` 是如何*同时* 作用于返回的 JSX 和事件处理函数中的!这种简便模式之所以有效,是因为事件处理函数["闭包"](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures)了渲染时声明的任何变量。 -Notice how `hasPrev` and `hasNext` are used *both* for the returned JSX and inside the event handlers! This handy pattern works because event handler functions ["close over"](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures) any variables declared while rendering. +注意 `hasPrev` 和 `hasNext` 是如何*同时* 作用于返回的 JSX 和事件处理函数中的!这种简便的模式之所以有效,是因为事件处理函数["闭包"](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures)了渲染时声明的变量。 -### Fix stuck form inputs +### 修复卡住的输入表单 当你输入字段时,什么也没有出现。这就像输入值被空字符串给“卡住”了。第一个 `` 的 `value` 设置为始终匹配 `firstName` 变量,第二个 `` 的 `value` 设置为始终匹配 `lastName` 变量。这是对的。两个输入框都有 `onChange` 事件处理函数,它尝试根据最新的用户输入(`e.target.value`)更新变量。但是,变量似乎并没有在重新渲染时“记住”它们的值。通过使用 state 变量来解决此问题。 @@ -1340,15 +1322,13 @@ h1 { margin-top: 10px; } -### Fix a crash +### 修复一个错误 -这是一个小表单,用于让用户留下一些反馈。当反馈被提交时,它应该显示一条感谢信息。但是,现在它会发生崩溃并显示错误消息“渲染的 hooks 比预期的少”。你能发现错误并修复它吗? -Here is a small form that is supposed to let the user leave some feedback. When the feedback is submitted, it's supposed to display a thank-you message. However, it crashes with an error message saying "Rendered fewer hooks than expected". Can you spot the mistake and fix it? +这是一个收集用户反馈的小表单。当反馈被提交时,它应该显示一条感谢信息。但是,现在它会发生崩溃并显示错误消息“渲染的 hooks 比预期的少”。你能发现错误并修复它吗? -对于 Hooks 在什么地方被调用,有任何限制吗?这个组件是否违反了任何规则? -Are there any limitations on _where_ Hooks may be called? Does this component break any rules? +Hooks 只允许在*什么地方* 调用?这个组件是否违反了任何规则? @@ -1386,8 +1366,7 @@ export default function FeedbackForm() { -Hooks 只能在组件函数的顶层调用。这里,第一个 `isSent` 定义遵循这个规则,但是 `message` 定义嵌套在一个条件语句中。将其移出条件语句以解决问题: -Hooks can only be called at the top level of the component function. Here, the first `isSent` definition follows this rule, but the `message` definition is nested in a condition. Move it out of the condition to fix the issue: +Hooks 只能在组件函数的顶层调用。这里,第一个 `isSent` 定义遵循这个规则,但是 `message` 的定义位于一个条件语句中。将其移出条件语句以解决问题: @@ -1423,7 +1402,6 @@ export default function FeedbackForm() { 请记住,必须在条件语句外并且始终以相同的顺序调用 Hook! -Remember, Hooks must be called unconditionally and always in the same order! 你还可以删除不必要的`else` 分支以减少嵌套。但要保证对 Hooks 的所有调用都发生在*第一个 `return` 前,这很重要。 @@ -1461,20 +1439,18 @@ export default function FeedbackForm() { -尝试移动第二个 `useState` 调用到 `if` 条件之后,并注意这如何再次破坏了它。 -Try moving the second `useState` call after the `if` condition and notice how this breaks it again. +尝试移动第二个 `useState` 调用到 `if` 条件之后,并要注意这会如何再次破坏它。 通常,以上类型的错误都会由 [`eslint-plugin-react-hooks`](https://www.npmjs.com/package/eslint-plugin-react-hooks) linter 规则捕获。如果在本地调试错误代码时没有看到错误,则需要在构建工具的配置文件中进行设置。 -### Remove unnecessary state +### 移除不必要的 state 当按钮被点击时,这个例子应该询问用户的名字,然后显示一个 alert 欢迎他们。你尝试使用 state 来保存名字,但由于某种原因,它始终显示“Hello, !”。 -要修复此代码,请删除不必要的 state 变量。(我们将在稍后讨论 [为什么以上代码不起作用](/learn/troubleshooting-state-updates#setting-state-does-not-update-variables)。) -(We will discuss about [why this didn't work](/learn/troubleshooting-state-updates#setting-state-does-not-update-variables) later.) +要修复此代码,请删除不必要的 state 变量。(我们将在稍后讨论 [为什么上述代码不起作用](/learn/troubleshooting-state-updates#setting-state-does-not-update-variables)。) 你能解释为什么这个 state 变量是不必要的吗? @@ -1503,8 +1479,7 @@ export default function FeedbackForm() { -以下是一个使用声明于需要她的函数中的一般 `name` 变量的固定版本: -Here is a fixed version that uses a regular `name` variable declared in the function that needs it: +以下是一个使用了一般变量 `name` 的固定版本,这个变量声明于需要它的函数中。 From 6c5870a64625312513c5344ffa2e5357c825324a Mon Sep 17 00:00:00 2001 From: zzwgh Date: Thu, 23 Feb 2023 15:15:03 +0800 Subject: [PATCH 4/8] fix: syntax error --- .../learn/state-a-components-memory.md | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/beta/src/content/learn/state-a-components-memory.md b/beta/src/content/learn/state-a-components-memory.md index dffec3d737..8a9488a8be 100644 --- a/beta/src/content/learn/state-a-components-memory.md +++ b/beta/src/content/learn/state-a-components-memory.md @@ -19,7 +19,7 @@ translators: -## 当一般变量不够时 {#when-a-regular-variable-isnt-enough} +## 当一般变量不够时 {/*when-a-regular-variable-isnt-enough*/} 以下是一个渲染雕塑图片的组件。点击“Next”按钮应该显示下一个雕塑并将 `index` 更改为 `1`,再次点击又更改为 `2`,以此类推。但这个组件现在**不起作用**(你可以试一试!): @@ -168,7 +168,7 @@ button { 1. **State 变量** 用于保存渲染间的数据。 2. **State setter 函数** 更新变量并触发 React 再次渲染组件。 -## 添加一个 state 变量 {#adding-a-state-variable} +## 添加一个 state 变量 {/*adding-a-state-variable*/} 要添加 state 变量,先从文件顶部的 React 中导入 `useState`: @@ -334,7 +334,7 @@ button { -### 遇见你的第一个 Hook {#meet-your-first-hook} +### 遇见你的第一个 Hook {/*meet-your-first-hook*/} 在 React 中,`useState` 以及任何其他以“`use`”开头的函数都被称为 **Hook**。 @@ -344,11 +344,11 @@ State 只是这些特性中的一个,你之后还会遇到其他 Hooks。 -**Hooks——以 `use` 开头的函数——只能在组件或[自定义 Hooks](/learn/reusing-logic-with-custom-hooks) 的最顶层调用。**你不能在条件语句、循环语句或其他嵌套函数内调用 Hooks。Hooks 是函数,但将它们视为关于组件需求的无条件声明会很有帮助。在组件顶部“use” React 特性,类似于在文件顶部“导入”模块。 +**Hooks——以 `use` 开头的函数——只能在组件或[自定义 Hooks](/learn/reusing-logic-with-custom-hooks) 的最顶层调用。** 你不能在条件语句、循环语句或其他嵌套函数内调用 Hooks。Hooks 是函数,但将它们视为关于组件需求的无条件声明会很有帮助。在组件顶部“use” React 特性,类似于在文件顶部“导入”模块。 -### 剖析 `useState` {#anatomy-of-usestate} +### 剖析 `useState` {/*anatomy-of-usestate*/} 当你调用 [`useState`](/reference/usestate) 时,你是在告诉 React 你想让这个组件记住一些东西: @@ -378,7 +378,7 @@ const [index, setIndex] = useState(0); 3. **组件进行第二次渲染。** React 仍然看到 `useState(0)`,但是因为 React *记住* 了你将 `index` 设置为了 `1`,它将返回 `[1, setIndex]`。 4. 以此类推! -## 赋予一个组件多个 state 变量 {#giving-a-component-multiple-state-variables} +## 赋予一个组件多个 state 变量 {/*giving-a-component-multiple-state-variables*/} 你可以在一个组件中拥有任意多种类型的 state 变量。该组件有两个 state 变量,一个数字 `index` 和一个布尔值 `showMore`,点击 “Show Details” 会改变 `showMore` 的值: @@ -523,6 +523,8 @@ button { +#### React 如何知道返回哪个 state {/*how-does-react-know-which-state-to-return*/} + 你可能已经注意到,`useState` 在调用时没有任何关于它引用的是*哪个* state 变量的信息。没有传递给 `useState` 的“标识符”,它是如何知道要返回哪个 state 变量呢?它是否依赖于解析函数之类的魔法?答案是否定的。 相反,为了使语法更简洁,**在同一组件的每次渲染中,Hooks 都依托于一个稳定的调用顺序**。这在实践中很有效,因为如果你遵循上面的规则(“只在顶层调用 Hooks”),Hooks 将始终以相同的顺序被调用。此外,[linter 插件](https://www.npmjs.com/package/eslint-plugin-react-hooks)也可以捕获大多数错误。 @@ -725,7 +727,7 @@ button { display: block; margin-bottom: 10px; } -## State 是独立且私有的 {#state-is-isolated-and-private} +## State 是独立且私有的 {/*state-is-isolated-and-private*/} State 是屏幕上组件实例内部的状态。换句话说,**如果你渲染同一个组件两次,每个副本都会有完全隔离的 state!**改变其中一个不会影响另一个。 @@ -910,7 +912,7 @@ button { -### 完成画廊组件 +#### 完成画廊组件 {/*complete-the-gallery*/} 当你在最后一个雕塑上按“Next”时,代码会发生崩溃。请修复逻辑以防止此崩溃。你可以尝试在事件处理函数中添加额外的逻辑,或在操作无法执行时禁用掉按钮。 @@ -1220,7 +1222,7 @@ img { width: 120px; height: 120px; } -### 修复卡住的输入表单 +#### 修复卡住的输入表单 {/*fix-stuck-form-inputs*/} 当你输入字段时,什么也没有出现。这就像输入值被空字符串给“卡住”了。第一个 `` 的 `value` 设置为始终匹配 `firstName` 变量,第二个 `` 的 `value` 设置为始终匹配 `lastName` 变量。这是对的。两个输入框都有 `onChange` 事件处理函数,它尝试根据最新的用户输入(`e.target.value`)更新变量。但是,变量似乎并没有在重新渲染时“记住”它们的值。通过使用 state 变量来解决此问题。 @@ -1322,7 +1324,7 @@ h1 { margin-top: 10px; } -### 修复一个错误 +#### 修复一个错误 {/*fix-a-crash*/} 这是一个收集用户反馈的小表单。当反馈被提交时,它应该显示一条感谢信息。但是,现在它会发生崩溃并显示错误消息“渲染的 hooks 比预期的少”。你能发现错误并修复它吗? @@ -1448,7 +1450,7 @@ export default function FeedbackForm() { -### 移除不必要的 state +#### 移除不必要的 state {/*remove-unnecessary-state*/} 当按钮被点击时,这个例子应该询问用户的名字,然后显示一个 alert 欢迎他们。你尝试使用 state 来保存名字,但由于某种原因,它始终显示“Hello, !”。 From bef65187bef1200b3518bdbcb7feacaaa58ea1ca Mon Sep 17 00:00:00 2001 From: zzwgh Date: Fri, 24 Feb 2023 04:02:49 +0800 Subject: [PATCH 5/8] chore: update --- .../learn/state-a-components-memory.md | 78 ++++++++++--------- 1 file changed, 40 insertions(+), 38 deletions(-) diff --git a/beta/src/content/learn/state-a-components-memory.md b/beta/src/content/learn/state-a-components-memory.md index 8a9488a8be..ba39294867 100644 --- a/beta/src/content/learn/state-a-components-memory.md +++ b/beta/src/content/learn/state-a-components-memory.md @@ -19,9 +19,9 @@ translators: -## 当一般变量不够时 {/*when-a-regular-variable-isnt-enough*/} +## 当普通的变量无法满足时 {/*when-a-regular-variable-isnt-enough*/} -以下是一个渲染雕塑图片的组件。点击“Next”按钮应该显示下一个雕塑并将 `index` 更改为 `1`,再次点击又更改为 `2`,以此类推。但这个组件现在**不起作用**(你可以试一试!): +以下是一个渲染雕塑图片的组件。点击 “Next” 按钮应该显示下一个雕塑并将 `index` 更改为 `1`,再次点击又更改为 `2`,以此类推。但这个组件现在**不起作用**(你可以试一试!): @@ -155,7 +155,7 @@ button { `handleClick()` 事件处理函数正在更新局部变量 `index`。但存在两个原因使得变化不可见: -1. **局部变量无法在多次渲染中持久保存。** 当 React 第二次渲染这个组件时,它会从头开始渲染——不考虑之前对局部变量的任何更改。 +1. **局部变量无法在多次渲染中持久保存。** 当 React 再次渲染这个组件时,它会从头开始渲染——不会考虑之前对局部变量的任何更改。 2. **更改局部变量不会触发渲染。** React 没有意识到它需要使用新数据再次渲染组件。 要使用新数据更新组件,需要做两件事: @@ -191,7 +191,7 @@ const [index, setIndex] = useState(0); `index` 是一个 state 变量,`setIndex` 是对应的 setter 函数。 -> 这里的 `[` 和 `]` 语法称为[数组解构](/learn/a-javascript-refresher#array-destructuring),它允许你从数组中读取值。 `useState` 返回的数组总是正好有两个项。 +> 这里的 `[` 和 `]` 语法称为[数组解构](/learn/a-javascript-refresher#array-destructuring),它允许你从数组中读取值。 `useState` 返回的数组总是正好有两项。 以下展示了它们在 `handleClick()` 中是如何共同起作用的: @@ -201,7 +201,7 @@ function handleClick() { } ``` -现在点击“Next”按钮切换当前雕塑: +现在点击 “Next” 按钮切换当前雕塑: @@ -338,13 +338,13 @@ button { 在 React 中,`useState` 以及任何其他以“`use`”开头的函数都被称为 **Hook**。 -Hooks 是特殊的函数,只在 React [渲染](/learn/render-and-commit#step-1-trigger-a-render)时有效(我们将在下一节详细介绍)。它们能让你“hook”到不同的 React 特性中去。 +Hooks 是特殊的函数,只在 React [渲染](/learn/render-and-commit#step-1-trigger-a-render)时有效(我们将在下一节详细介绍)。它们能让你 “hook” 到不同的 React 特性中去。 State 只是这些特性中的一个,你之后还会遇到其他 Hooks。 -**Hooks——以 `use` 开头的函数——只能在组件或[自定义 Hooks](/learn/reusing-logic-with-custom-hooks) 的最顶层调用。** 你不能在条件语句、循环语句或其他嵌套函数内调用 Hooks。Hooks 是函数,但将它们视为关于组件需求的无条件声明会很有帮助。在组件顶部“use” React 特性,类似于在文件顶部“导入”模块。 +**Hooks——以 `use` 开头的函数——只能在组件或[自定义 Hooks](/learn/reusing-logic-with-custom-hooks) 的最顶层调用。** 你不能在条件语句、循环语句或其他嵌套函数内调用 Hooks。Hooks 是函数,但将它们视为关于组件需求的无条件声明会很有帮助。在组件顶部 “use” React 特性,类似于在文件顶部“导入”模块。 @@ -374,7 +374,7 @@ const [index, setIndex] = useState(0); ``` 1. **组件进行第一次渲染。** 因为你将 `0` 作为 `index` 的初始值传递给 `useState`,它将返回 `[0, setIndex]`。 React 记住 `0` 是最新的 state 值。 -2. **你更新了 state。**当用户点击按钮时,它会调用 `setIndex(index + 1)`。 `index` 是 `0`,所以它是 `setIndex(1)`。这告诉 React 现在记住 `index` 是 `1` 并触发另一个渲染。 +2. **你更新了 state。**当用户点击按钮时,它会调用 `setIndex(index + 1)`。 `index` 是 `0`,所以它是 `setIndex(1)`。这告诉 React 现在记住 `index` 是 `1` 并触发下一次渲染。 3. **组件进行第二次渲染。** React 仍然看到 `useState(0)`,但是因为 React *记住* 了你将 `index` 设置为了 `1`,它将返回 `[1, setIndex]`。 4. 以此类推! @@ -519,7 +519,7 @@ button { -如果它们不相关,那么存在多个 state 变量是一个好主意,例如本例中的 `index` 和 `showMore`。但是,如果你发现经常同时更改两个 state 变量,那么最好将它们合并为一个。例如,如果你有一个包含多个字段的表单,那么拥有一个值为对象的 state 变量比每个字段对应一个 state 变量更方便。 [选择 state 结构](/learn/choosing-the-state-structure)在这方面有更多提示。 +如果它们不相关,那么存在多个 state 变量是一个好主意,例如本例中的 `index` 和 `showMore`。但是,如果你发现经常同时更改两个 state 变量,那么最好将它们合并为一个。例如,如果你有一个包含多个字段的表单,那么有一个值为对象的 state 变量比每个字段对应一个 state 变量更方便。 [选择 state 结构](/learn/choosing-the-state-structure)在这方面有更多提示。 @@ -529,9 +529,9 @@ button { 相反,为了使语法更简洁,**在同一组件的每次渲染中,Hooks 都依托于一个稳定的调用顺序**。这在实践中很有效,因为如果你遵循上面的规则(“只在顶层调用 Hooks”),Hooks 将始终以相同的顺序被调用。此外,[linter 插件](https://www.npmjs.com/package/eslint-plugin-react-hooks)也可以捕获大多数错误。 -在内部,React 为每个组件保存了一个数组,其中每一项都是一个 state 对。它维护当前 state 对的索引值,在渲染之前将其设置为“0”。每次调用 useState 时,React 都会为你提供一个 state 对并增加索引值。你可以在文章 [React Hooks: not magic, just arrays](https://medium.com/@ryardley/react-hooks-not-magic-just-arrays-cd4f1857236e)中阅读有关此机制的更多信息。 +在 React 内部,为每个组件保存了一个数组,其中每一项都是一个 state 对。它维护当前 state 对的索引值,在渲染之前将其设置为 “0”。每次调用 useState 时,React 都会为你提供一个 state 对并增加索引值。你可以在文章 [React Hooks: not magic, just arrays](https://medium.com/@ryardley/react-hooks-not-magic-just-arrays-cd4f1857236e)中阅读有关此机制的更多信息。 -这个例子**不使用 React**,但它让你了解 `useState` 在内部是如何工作的: +这个例子**没有使用 React**,但它让你了解 `useState` 在内部是如何工作的: @@ -539,37 +539,39 @@ button { let componentHooks = []; let currentHookIndex = 0; -// How useState works inside React (simplified). +// useState 在 React 中是如何工作的(简化版) function useState(initialState) { let pair = componentHooks[currentHookIndex]; if (pair) { - // This is not the first render, - // so the state pair already exists. - // Return it and prepare for next Hook call. + // 这不是第一次渲染 + // 所以 state pair 已经存在 + // 将其返回并为下一次 hook 的调用做准备 currentHookIndex++; return pair; } - // This is the first time we're rendering, - // so create a state pair and store it. + // 这是我们第一次进行渲染 + // 所以新建一个 state pair 然后存储它 pair = [initialState, setState]; function setState(nextState) { - // When the user requests a state change, - // put the new value into the pair. + // 当用户发起 state 的变更, + // 把新的值放入 pair 中 pair[0] = nextState; updateDOM(); } // Store the pair for future renders // and prepare for the next Hook call. + // 存储这个 pair 用于将来的渲染 + // 并且为下一次 hook 的调用做准备 componentHooks[currentHookIndex] = pair; currentHookIndex++; return pair; } function Gallery() { - // Each useState() call will get the next pair. + // 每次调用 useState() 都会得到新的 pair const [index, setIndex] = useState(0); const [showMore, setShowMore] = useState(false); @@ -582,8 +584,8 @@ function Gallery() { } let sculpture = sculptureList[index]; - // This example doesn't use React, so - // return an output object instead of JSX. + // 这个例子没有使用 React,所以 + // 返回一个对象而不是 JSX return { onNextClick: handleNextClick, onMoreClick: handleMoreClick, @@ -597,13 +599,13 @@ function Gallery() { } function updateDOM() { - // Reset the current Hook index - // before rendering the component. + // 在渲染组件之前 + // 重置当前 Hook 的下标 currentHookIndex = 0; let output = Gallery(); - // Update the DOM to match the output. - // This is the part React does for you. + // 更新 DOM 以匹配输出结果 + // 这部分工作由 React 为你完成 nextButton.onclick = output.onNextClick; header.textContent = output.header; moreButton.onclick = output.onMoreClick; @@ -697,7 +699,7 @@ let sculptureList = [{ alt: 'A group of bronze hippo sculptures emerging from the sett sidewalk as if they were swimming.' }]; -// Make UI match the initial state. +// 使 UI 匹配当前 state updateDOM(); ``` @@ -727,7 +729,7 @@ button { display: block; margin-bottom: 10px; } -## State 是独立且私有的 {/*state-is-isolated-and-private*/} +## State 是隔离且私有的 {/*state-is-isolated-and-private*/} State 是屏幕上组件实例内部的状态。换句话说,**如果你渲染同一个组件两次,每个副本都会有完全隔离的 state!**改变其中一个不会影响另一个。 @@ -890,18 +892,18 @@ button { -这就是 state 与声明在模块顶部的一般变量不同的原因。 State 与特定的函数调用或在代码中的位置无关,它的作用域“只限于”屏幕上的某块特定区域。你渲染了两个 `` 组件,所以它们的 state 是分开存储的。 +这就是 state 与声明在模块顶部的普通变量不同的原因。 State 不依赖于特定的函数调用或在代码中的位置,它的作用域“只限于”屏幕上的某块特定区域。你渲染了两个 `` 组件,所以它们的 state 是分别存储的。 -还要注意 `Page` 组件“不知道”关于 `Gallery` state 的任何信息,甚至不知道它是否有任何 state。与 props 不同,**state 完全私有于声明它的组件**。父组件无法更改它。这使你可以向任何组件添加或删除 state,而不会影响其余组件。 +还要注意 `Page` 组件“不知道”关于 `Gallery` state 的任何信息,甚至不知道它是否有任何 state。与 props 不同,**state 完全私有于声明它的组件**。父组件无法更改它。这使你可以向任何组件添加或删除 state,而不会影响其他组件。 -如果你希望两个画廊保持其 states 同步怎么办?在 React 中执行此操作的正确方法是从子组件中*删除* state 并将其添加到离它们最近的共享父组件中。接下来的几节将专注于组织单个组件的 state,但我们将在[组件间共享 state](/learn/sharing-state-between-components)中回到这个主题。 +如果你希望两个画廊保持其 states 同步怎么办?在 React 中执行此操作的正确方法是从子组件中*删除* state 并将其添加到离它们最近的共享父组件中。接下来的几节将专注于组织单个组件的 state,但我们将在[组件间共享 state](/learn/sharing-state-between-components) 中回到这个主题。 * 当一个组件需要在多次渲染间“记住”某些信息时使用 state 变量。 * State 变量是通过调用 `useState` Hook 来声明的。 -* Hooks 是以 `use` 开头的特殊函数。它们能让你“hook”到像 state 这样的 React 特性中。 -* Hooks 可能会让你想起 imports:它们需要被无条件调用。Hooks,包括 `useState`,仅在组件或另一个 Hook 的顶层被调用才有效。 +* Hooks 是以 `use` 开头的特殊函数。它们能让你 “hook” 到像 state 这样的 React 特性中。 +* Hooks 可能会让你想起 imports:它们需要在非条件语句中调用。调用 Hooks 时,包括 `useState`,仅在组件或另一个 Hook 的顶层被调用才有效。 * `useState` Hook 返回一对值:当前 state 和更新它的函数。 * 你可以拥有多个 state 变量。在内部,React 按顺序匹配它们。 * State 是组件私有的。如果你在两个地方渲染它,则每个副本都有独属于自己的 state。 @@ -914,9 +916,9 @@ button { #### 完成画廊组件 {/*complete-the-gallery*/} -当你在最后一个雕塑上按“Next”时,代码会发生崩溃。请修复逻辑以防止此崩溃。你可以尝试在事件处理函数中添加额外的逻辑,或在操作无法执行时禁用掉按钮。 +当你在最后一个雕塑上按 “Next” 时,代码会发生崩溃。请修复逻辑以防止此崩溃。你可以尝试在事件处理函数中添加额外的逻辑,或在操作无法执行时禁用掉按钮。 -修复崩溃后,添加一个显示上一个雕塑的“Previous”按钮。同样地,确保它不在第一个雕塑里发生崩溃。 +修复崩溃后,添加一个显示上一个雕塑的 “Previous” 按钮。同样地,确保它不在第一个雕塑里发生崩溃。 @@ -1455,7 +1457,7 @@ export default function FeedbackForm() { 当按钮被点击时,这个例子应该询问用户的名字,然后显示一个 alert 欢迎他们。你尝试使用 state 来保存名字,但由于某种原因,它始终显示“Hello, !”。 -要修复此代码,请删除不必要的 state 变量。(我们将在稍后讨论 [为什么上述代码不起作用](/learn/troubleshooting-state-updates#setting-state-does-not-update-variables)。) +要修复此代码,请删除不必要的 state 变量。(我们将在稍后讨论[为什么上述代码不起作用](/learn/troubleshooting-state-updates#setting-state-does-not-update-variables)。) 你能解释为什么这个 state 变量是不必要的吗? @@ -1484,7 +1486,7 @@ export default function FeedbackForm() { -以下是一个使用了一般变量 `name` 的固定版本,这个变量声明于需要它的函数中。 +以下是一个使用了普通变量 `name` 的固定版本,这个变量声明于需要它的函数中。 @@ -1507,7 +1509,7 @@ export default function FeedbackForm() { -State 变量仅用于在组件重渲染时保存信息。在单个事件处理函数中,一般变量就足够了。当一般变量运行良好时,不要引入 state 变量。 +State 变量仅用于在组件重渲染时保存信息。在单个事件处理函数中,普通变量就足够了。当普通变量运行良好时,不要引入 state 变量。 From e41a0081146c8b36dc17c6d6fa9c0703ccf79545 Mon Sep 17 00:00:00 2001 From: zzwgh Date: Fri, 24 Feb 2023 13:54:06 +0800 Subject: [PATCH 6/8] docs(cn): resolve code reviews --- beta/src/content/learn/state-a-components-memory.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/beta/src/content/learn/state-a-components-memory.md b/beta/src/content/learn/state-a-components-memory.md index ba39294867..135438186a 100644 --- a/beta/src/content/learn/state-a-components-memory.md +++ b/beta/src/content/learn/state-a-components-memory.md @@ -2,6 +2,7 @@ title: "State:组件的记忆" translators: - zzw + - x-cold --- @@ -160,7 +161,7 @@ button { 要使用新数据更新组件,需要做两件事: -1. **保留**渲染之间的数据。 +1. **保留** 渲染之间的数据。 2. **触发** React 使用新数据渲染组件(重新渲染)。 [`useState`](/reference/usestate) Hook 提供了这两个功能: From 10e054acfdad0d2e4de4549062db6a53d2bf90cb Mon Sep 17 00:00:00 2001 From: Xavi Lee Date: Mon, 27 Feb 2023 23:21:30 +0800 Subject: [PATCH 7/8] Apply suggestions from code review Co-authored-by: TimLi --- .../content/learn/state-a-components-memory.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/beta/src/content/learn/state-a-components-memory.md b/beta/src/content/learn/state-a-components-memory.md index 135438186a..08ad5d1b9d 100644 --- a/beta/src/content/learn/state-a-components-memory.md +++ b/beta/src/content/learn/state-a-components-memory.md @@ -341,11 +341,11 @@ button { Hooks 是特殊的函数,只在 React [渲染](/learn/render-and-commit#step-1-trigger-a-render)时有效(我们将在下一节详细介绍)。它们能让你 “hook” 到不同的 React 特性中去。 -State 只是这些特性中的一个,你之后还会遇到其他 Hooks。 +State 只是这些特性中的一个,你之后还会遇到其他 Hook。 -**Hooks——以 `use` 开头的函数——只能在组件或[自定义 Hooks](/learn/reusing-logic-with-custom-hooks) 的最顶层调用。** 你不能在条件语句、循环语句或其他嵌套函数内调用 Hooks。Hooks 是函数,但将它们视为关于组件需求的无条件声明会很有帮助。在组件顶部 “use” React 特性,类似于在文件顶部“导入”模块。 +**Hooks ——以 `use` 开头的函数——只能在组件或[自定义 Hook](/learn/reusing-logic-with-custom-hooks) 的最顶层调用。** 你不能在条件语句、循环语句或其他嵌套函数内调用 Hook。Hook 是函数,但将它们视为关于组件需求的无条件声明会很有帮助。在组件顶部 “use” React 特性,类似于在文件顶部“导入”模块。 @@ -365,7 +365,7 @@ const [index, setIndex] = useState(0); 每次你的组件渲染时,`useState` 都会给你一个包含两个值的数组: -1. **state 变量** (`index`) 与你存储的值。 +1. **state 变量** (`index`) 会保存上次渲染的值。 2. **state setter 函数** (`setIndex`) 可以更新 state 变量并触发 React 重新渲染组件。 以下是实际发生的情况: @@ -903,8 +903,8 @@ button { * 当一个组件需要在多次渲染间“记住”某些信息时使用 state 变量。 * State 变量是通过调用 `useState` Hook 来声明的。 -* Hooks 是以 `use` 开头的特殊函数。它们能让你 “hook” 到像 state 这样的 React 特性中。 -* Hooks 可能会让你想起 imports:它们需要在非条件语句中调用。调用 Hooks 时,包括 `useState`,仅在组件或另一个 Hook 的顶层被调用才有效。 +* Hook 是以 `use` 开头的特殊函数。它们能让你 “hook” 到像 state 这样的 React 特性中。 +* Hook 可能会让你想起 import:它们需要在非条件语句中调用。调用 Hook 时,包括 `useState`,仅在组件或另一个 Hook 的顶层被调用才有效。 * `useState` Hook 返回一对值:当前 state 和更新它的函数。 * 你可以拥有多个 state 变量。在内部,React 按顺序匹配它们。 * State 是组件私有的。如果你在两个地方渲染它,则每个副本都有独属于自己的 state。 @@ -1276,7 +1276,7 @@ h1 { margin-top: 10px; } -首先,从 React 导入 `useState`。然后用 `useState` 声明的 state 变量替换 `firstName` 和 `lastName`。最后,用 `setFirstName(...)` 替换每个 `firstName = ...` 赋值,并对 `lastName` 做同样的事情。不要忘记更新 `handleReset`,以便重置按钮。 +首先,从 React 导入 `useState`。然后用 `useState` 声明的 state 变量替换 `firstName` 和 `lastName`。最后,用 `setFirstName(...)` 替换每个 `firstName = ...` 赋值,并对 `lastName` 做同样的事情。不要忘记更新 `handleReset`,以使重置按钮生效。 @@ -1333,7 +1333,7 @@ h1 { margin-top: 10px; } -Hooks 只允许在*什么地方* 调用?这个组件是否违反了任何规则?检查是否有注释禁用了 linter 检查--这往往是 bug 的藏身之处! +Hook 只允许在*什么地方* 调用?这个组件是否违反了任何规则?检查是否有注释禁用了 linter 检查--这往往是 bug 的藏身之处! @@ -1372,7 +1372,7 @@ export default function FeedbackForm() { -Hooks 只能在组件函数的顶层调用。这里,第一个 `isSent` 定义遵循这个规则,但是 `message` 的定义位于一个条件语句中。 +Hook 只能在组件函数的顶层调用。这里,第一个 `isSent` 定义遵循这个规则,但是 `message` 的定义位于一个条件语句中。 将其移出条件语句以解决问题: @@ -1412,7 +1412,7 @@ export default function FeedbackForm() { 请记住,必须在条件语句外并且始终以相同的顺序调用 Hook! -你还可以删除不必要的`else` 分支以减少嵌套。但要保证对 Hooks 的所有调用都发生在*第一个 `return` 前,这很重要。 +你还可以删除不必要的 `else` 分支以减少嵌套。但要保证对 Hook 的所有调用都发生在*第一个 `return` 前,这很重要。 From 8ff5f1c516da308170ff3eb78e9115d3b7650b92 Mon Sep 17 00:00:00 2001 From: Xavi Lee Date: Mon, 27 Feb 2023 23:22:22 +0800 Subject: [PATCH 8/8] Update beta/src/content/learn/state-a-components-memory.md Co-authored-by: TimLi --- beta/src/content/learn/state-a-components-memory.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/beta/src/content/learn/state-a-components-memory.md b/beta/src/content/learn/state-a-components-memory.md index 08ad5d1b9d..f4e9097c3c 100644 --- a/beta/src/content/learn/state-a-components-memory.md +++ b/beta/src/content/learn/state-a-components-memory.md @@ -339,7 +339,7 @@ button { 在 React 中,`useState` 以及任何其他以“`use`”开头的函数都被称为 **Hook**。 -Hooks 是特殊的函数,只在 React [渲染](/learn/render-and-commit#step-1-trigger-a-render)时有效(我们将在下一节详细介绍)。它们能让你 “hook” 到不同的 React 特性中去。 +Hook 是特殊的函数,只在 React [渲染](/learn/render-and-commit#step-1-trigger-a-render)时有效(我们将在下一节详细介绍)。它们能让你 “hook” 到不同的 React 特性中去。 State 只是这些特性中的一个,你之后还会遇到其他 Hook。