使用 State(状态) Hook

Hooks 是一项新功能提案,可让您在不编写类的情况下使用 state(状态) 和其他 React 功能。它们目前处于 React v16.7.0-alpha 中,并在 ​​一个开放RFC​​ 中进行讨论。

在 ​​介绍 Hooks​​ 中用这个例子介绍了 Hooks :

import { useState } from 'react';

function Example() {
// Declare a new state variable, which we'll call "count"
const [count, setCount] = useState(0);

return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}

我们将通过将这段代码与一个等效的类示例进行比较来学习 Hooks。

等效的类示例

如果您之前在 React 中使用过 classes(类),那么这段代码应该看起来很熟悉:

class Example extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}

render() {
return (
<div>
<p>You clicked {this.state.count} times</p>
<button onClick={() => this.setState({ count: this.state.count + 1 })}>
Click me
</button>
</div>
);
}
}

状态以 ​​{ count: 0 }​​​ 开始,当用户通过单击按钮调用 ​​this.setState()​​​时,我们会增加​​state.count​​ 。我们将在整个页面中使用这个类的片段。

注意

您可能想知道为什么我们在这里使用计数器而不是更现实的例子。这是为了帮助我们专注于API,同时我们仍在使用 Hooks 迈出第一步。

Hooks 和 函数式组件

提醒一下,React 中的函数组件如下所示:

const Example = (props) => {
// You can use Hooks here!
return <div />;
}

或者是这样的:

function Example(props) {
// You can use Hooks here!
return <div />;
}

您可能以前将这些称为“无状态组件”。 我们现在介绍的这些组件将具有 React state(状态) 的能力,所以我们更喜欢称他为 “函数式组件”。

Hooks 在 classes(类) 内  起作用。 但是你可以使用它们来取代编写类。

什么是 Hook ?

我们的新示例首先从 React 导入 ​​useState​​ Hook 开始:

import { useState } from 'react';

function Example() {
// ...
}

什么是 Hook ? Hook是一种特殊函数,可让你 “接入” React 功能。 例如,​​useState​​ 是一个 Hook,允许您将 React state(状态) 添加到函数式组件中。 我们稍后会学习其他的 Hooks。

我什么时候使用 Hook? 如果你编写一个函数式组件并意识到你需要为它添加一些 state(状态) ,那么之前你必须将它转换为一个 classes(类) 。 但是现在,您可以在现有函数式组件中使用 Hook 。 我们现在要做到这一点!

注意:

关于在何处可以使用 Hook 并且不能在组件中使用 Hook ,有一些特殊规则。 我们将在 ​​Hooks 规则​​ 中学习这些特殊规则。

声明一个 state(状态) 变量

在类中,我们通过在构造函数中将 ​​this.state​​​ 设置为 ​​{ count: 0 }​​​ 来将 ​​count​​​ state(状态) 初始化为 ​​0​​ :

class Example extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}

在函数式组件中,我们没有 ​​this​​​ ,所以我们不能分配或读取 ​​this.state​​​ 。相反,我们可以直接在组件内部调用 ​​useState​​ Hook:

import { useState } from 'react';

function Example() {
// Declare a new state variable, which we'll call "count"
const [count, setCount] = useState(0);

调用 useState 有什么作用? 它声明了一个 “state(状态)变量”。 我们的变量叫做 ​​count​​​,但我们可以称之为其他任何东西,比如 ​​banana​​​。 这是一种在函数调用之间“保留”某些值的方法 - ​​useState​​​ 提供了和使用在类中 ​​this.state​​ 完全相同功能的新方法。 通常,当函数退出时变量就会“销毁”,但 React 会保留 state(状态) 变量。

我们传递给 useState 的参数是什么? ​​seState()​​​ Hook 惟一参数是初始 state(状态) 。与 classes(类) 不同,这里的 state(状态) 不一定是对象。他可以是任何我们需要的内容,比如数字,字符串等。在我们的示例中,我们只需要一个数字来表示用户点击的次数,因此将 ​​0​​​ 作为变量的初始状态。(如果我们想在状态中存储两个不同的值,我们将调用 ​​seState()​​两次。)

useState返回的是什么? 它返回一对值:当前 state(状态) 和更新它的函数。 这就是我们编写 ​​const [count, setCount] = useState()​​​ 的原因。 这与类中的 ​​this.state.count​​​ 和 ​​this.setState​​​ 类似,只不过它们是成对的。 如果您不熟悉我们使用的语法,我们将 ​​在本页底部回到着重说明​​。

现在我们知道了 ​​useState​​ Hook 的作用,我们的例子应该更有说明意义:

import { useState } from 'react';

function Example() {
// Declare a new state variable, which we'll call "count"
const [count, setCount] = useState(0);

我们声明一个名为 ​​count​​​ 的 state(状态)变量,并将其设置为 ​​0​​​ 。React 将记住它在重新渲染之间的当前值,并为我们的函数提供最新的值。如果我们想要更新当前 ​​count​​​ ,我们可以调用 ​​setCount​​。

注意

您可能想知道:为什么 ​​useState​​​ 没有命名为 ​​createState​​ ?

“Create” 不是非常准确,因为 state(状态) 仅在我们组件第一次渲染时创建。 在下一次渲染期间,​​useState​​​ 为我们提供了当前 state(状态) 。 否则它根本不会是 “state(状态)” ! Hook 名称总是以 ​​use​​​ 开头也是有原因的。我们将在后面的 ​​Hooks 规则​​ 中了解。

读取 state(状态)

当我们想要在类中显示当前计数时,我们使用 ​​this.state.count​​ 读取:

  <p>You clicked {this.state.count} times</p>

在函数中,我们直接使用 ​​count​​ 读取:

  <p>You clicked {count} times</p>

更新 state(状态)

在类中,我们需要调用 ​​this.setState()​​​ 来更新 ​​count​​ 状态:

  <button onClick={() => this.setState({ count: this.state.count + 1 })}>
Click me
</button>

在函数中,我们已经将 ​​setCount​​​ 和 ​​count​​​ 作为变量,因此我们不需要 ​​this​​ :

  <button onClick={() => setCount(count + 1)}>
Click me
</button>

概括

现在让我们用一行一行地回顾一下我们所学到的知识,并检查我们是否已经理解。

 1:  import { useState } from 'react';
2:
3: function Example() {
4: const [count, setCount] = useState(0);
5:
6: return (
7: <div>
8: <p>You clicked {count} times</p>
9: <button onClick={() => setCount(count + 1)}>
10: Click me
11: </button>
12: </div>
13: );
14: }
  • 第1行:我们从 React import(导入)​​useState​​ Hook。 它允许我们在一个函数组件中保持本地state(状态)。
  • 第4行:在​​Example​​​ 组件中,我们通过调用​​useState​​​ Hook来声明一个新的 state(状态) 变量。它返回一对值,我们给它们命名。我们调用变量​​count​​​ ,因为它包含按钮单击次数。我们通过传递​​0​​​ 作为惟一的​​useState​​​ 参数,将其初始化为​​0​​​。它允许我们更新计数,因此我们将其命名为​​setCount​​。
  • 第9行:当用户点击时,我们使用新值调用​​setCount​​​ 。 然后,React 将重新渲染 Example 组件,并将新​​count​​ 值传递给它。

乍一看,似乎有很多东西需要考虑。别着急! 如果你对上面的解释中有困惑,再看一遍上面的代码,试着从头到尾读一遍。我们保证,一旦您试图“忘记” state(状态) 如何在 class(类) 中工作,并以全新的眼光看待这段代码,它就会有意义。

提示:方括号意味着什么?

当我们声明一个 state(状态) 变量时,您可能已经注意到方括号:

  const [count, setCount] = useState(0);

左侧的名称不是 React API 的一部分。您可以根据自己的需求 命名自己的 state(状态) 变量:

  const [fruit, setFruit] = useState('banana');

方括号语法其实是 JavaScript “数组解构” 语法。这意味着我们正在创建两个新变量 ​​fruit​​​ 和​​setFruit​​​ ,其中 ​​fruit​​​ 设置为 ​​useState​​​ 是第一个返回值,​​setFruit​​ 是第二个返回值。它相当于下面这段代码:

  var fruitStateVariable = useState('banana'); // Returns a pair
var fruit = fruitStateVariable[0]; // First item in a pair
var setFruit = fruitStateVariable[1]; // Second item in a pair

当我们使用 ​​useState​​​ 声明一个 state(状态) 变量时,它返回一个对(pair) - 一个包含两个项元素的数组。第一项元素是当前值,第二项元素是允许我们更新第一项元素值的函数。使用 ​​[0]​​​ 和 ​​[1]​​ 访问它们有点令人困惑,因为它们有特定的含义。这就是为什么我们使用数组解构的原因。

注意

您可能很好奇,React 是如何知道哪个组件对应哪个 ​​useState​​​,因为我们没有将相关的任何内容传递给React。 我们将在FAQ部分回答 ​​这个问题​​ 和许多其他问题。

提示:使用多个 state(状态) 变量

将 state(状态) 变量 声明为一对 ​​[something, setSomething]​​ 也很方便,因为如果我们想使用多个状态变量,它可以为 不同 的 state(状态) 变量赋予不同的名称:

function ExampleWithManyStates() {
// Declare multiple state variables!
const [age, setAge] = useState(42);
const [fruit, setFruit] = useState('banana');
const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);

在上面的组件中,我们将 ​​age​​​ ,​​fruit​​​ 和 ​​todos​​ 作为局部变量,我们可以单独更新它们:

  function handleOrangeClick() {
// Similar to this.setState({ fruit: 'orange' })
setFruit('orange');
}

您不必使用很多 state(状态) 变量。 状态变量可以很好地保存对象和数组,因此您仍然可以将相关数据组合在一起。 但是,与 class(类) 中的 ​​this.setState​​ 不同,更新状态变量总是替换它,而不是合并它。

我们 ​​在FAQ中​​ 提供了有关拆分状态变量的更多建议。

下一步

在这个页面上,我们了解了 React 提供的一个名为 ​​useState​​ 的 Hook 。 我们有时也会将其称为 “State(状态) Hook” 。 它允许我们将本地 state(状态) 添加到 React 函数式组件 - 这是我们第一次做到了!

我们还了解了 Hooks 的更多内容。 Hooks 是让您的函数式组件 “接入” React 功能的函数。 他们的名字总是以 ​​use​​ 开头,还有更多我们还没见过的 Hooks 。

现在让我们继续 学习下一个 Hook :useEffect​。 它允许您在组件中执行副作用(side effects),类似于类中的生命周期方法。

​Edit this page​

​使用 State(状态) Hook – React 中文文档 v16.6.3​