State: A Component’s Memory

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.

carousel /’kærə’sɛl/ 轮播,旋转sculpture /ˈskʌlptʃər/ 雕刻, 雕塑, 雕刻品

You will learn

  • How to add a state variable with the useState Hook(如何使用 useState Hook 添加 state 变量)
  • What pair of values the useState Hook returns(useState Hook 返回哪一对值)
  • How to add more than one state variable
  • Why state is called local(为什么 state 被称作是局部的)

When a regular variable isn’t enough (当普通的变量无法满足时)

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!)【点击 “Next” 按钮应该显示下一个雕塑并将 index 更改为 1,再次点击又更改为 2,以此类推。但这个组件现在不起作用(你可以试一试!)==》为啥不起作用呢?因为你每次点击按钮,就会重新渲染页面,而index是个局部变量。】:

The handleClick event handler is updating a local variable, index. But two things prevent that change from being visible:

  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. Retain the data between renders.(保留 渲染之间的数据
  2. Trigger React to render the component with new data (re-rendering).

The useState Hook provides those two things:

  1. state variable to retain the data between renders.
  2. state setter function to update the variable and trigger React to render the component again.(State setter 函数 更新变量并触发 React 再次渲染组件。

Adding a state variable 

To add a state variable, import useState from React at the top of the file(要添加 state 变量,先从文件顶部的 React 中导入 useState):

index is a state variable and setIndex is the setter function.

index 是一个 state 变量,setIndex 是对应的 setter 函数。██████

The [ and ] syntax here is called array destructuring and it lets you read values from an array. The array returned by useState always has exactly two items.(这里的 [] 语法称为数组解构,它允许你从数组中读取值。 useState 返回的数组总是正好有两项。

Now clicking the “Next” button switches the current sculpture:

Meet your first Hook 

In React, useState, as well as any other function starting with “use”, is called a Hook.(在 React 中,useState 以及任何其他以“use”开头的函数都被称为 Hook。

Hooks are special functions that are only available while React is rendering (which we’ll get into in more detail on the next page). They let you “hook into” different React features.(Hook 是特殊的函数,只在 React 渲染时有效。它们能让你 “hook” 到不同的 React 特性中去。

State is just one of those features, but you will meet the other Hooks later.

Pitfall

Hooks—functions starting with use—can only be called at the top level of your components or your own 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 开头的函数——只能在组件或自定义 Hook 的最顶层调用。 你不能在条件语句、循环语句或其他嵌套函数内调用 Hook。Hook 是函数,但将它们视为关于组件需求的无条件声明会很有帮助。在组件顶部 “use” React 特性,类似于在文件顶部“导入”模块。

Anatomy of useState (剖析 useState )

When you call useState, you are telling React that you want this component to remember something:

In this case, you want React to remember index.

Note

The convention(惯例) is to name this pair like const [something, setSomething]. You could name it anything you like, but conventions make things easier to understand across projects.(惯例是将这对返回值命名为 const [thing, setThing]。你也可以将其命名为任何你喜欢的名称,但遵照约定俗成能使跨项目合作更易理解。)

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).

Every time your component renders, useState gives you an array containing two values(每次你的组件渲染时,useState 都会给你一个包含两个值的数组):

  1. The state variable (index) with the value you stored.(state 变量 (index) 会保存上次渲染的值
  2. The state setter function (setIndex) which can update the state variable and trigger React to render the component again.(state setter 函数 (setIndex) 可以更新 state 变量并触发 React 重新渲染组件

Here’s how that happens in action:

  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 

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”:

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 easier to combine them into 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. Read Choosing the State Structure for more tips.

How does React know which state to return? (React 如何知道返回哪个 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.

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 catches most mistakes.

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.

This example doesn’t use React but it gives you an idea of how useState works internally: (具体例子见:https://zh-hans.react.dev/learn/state-a-components-memory

你可能已经注意到,useState 在调用时没有任何关于它引用的是哪个 state 变量的信息。没有传递给 useState 的“标识符”,它是如何知道要返回哪个 state 变量呢?它是否依赖于解析函数之类的魔法?答案是否定的。

相反,为了使语法更简洁,在同一组件的每次渲染中,Hooks 都依托于一个稳定的调用顺序。这在实践中很有效,因为如果你遵循上面的规则(“只在顶层调用 Hooks”),Hooks 将始终以相同的顺序被调用。此外,linter 插件也可以捕获大多数错误。

在 React 内部,为每个组件保存了一个数组,其中每一项都是一个 state 对。它维护当前 state 对的索引值,在渲染之前将其设置为 “0”。每次调用 useState 时,React 都会为你提供一个 state 对并增加索引值。你可以在文章 React Hooks: not magic, just arrays中阅读有关此机制的更多信息。

State is isolated and private (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.

In this example, the Gallery component from earlier is rendered twice with no changes to its logic.

This is what makes state different from regular variables that you might declare at the top of your module(这就是 state 与声明在模块顶部的普通变量不同的原因。). 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(State 不依赖于特定的函数调用或在代码中的位置,它的作用域“只限于”屏幕上的某块特定区域。). You rendered two <Gallery /> components, so their state is stored separately(你渲染了两个 <Gallery /> 组件,所以它们的 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.

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.

Recap

  • 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.
  • 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.
  • 当一个组件需要在多次渲染间“记住”某些信息时使用 state 变量。
  • State 变量是通过调用 useState Hook 来声明的。
  • Hook 是以 use 开头的特殊函数。它们能让你 “hook” 到像 state 这样的 React 特性中。
  • Hook 可能会让你想起 import:它们需要在非条件语句中调用。调用 Hook 时,包括 useState,仅在组件或另一个 Hook 的顶层被调用才有效。
  • useState Hook 返回一对值:当前 state 和更新它的函数。
  • 你可以拥有多个 state 变量。在内部,React 按顺序匹配它们。
  • State 是组件私有的。如果你在两个地方渲染它,则每个副本都有独属于自己的 state。

参:https://zh-hans.react.dev/learn/state-a-components-memory

码先生
Author: 码先生

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注