使用 State(状态) Hook
Hooks 是一项新功能提案,可让您在不编写类的情况下使用 state(状态) 和其他 React 功能。它们目前处于 React v16.7.0-alpha 中,并在 一个开放RFC 中进行讨论。
在 介绍 Hooks 中用这个例子介绍了 Hooks :
我们将通过将这段代码与一个等效的类示例进行比较来学习 Hooks。
等效的类示例
如果您之前在 React 中使用过 classes(类),那么这段代码应该看起来很熟悉:
状态以 { count: 0 }
开始,当用户通过单击按钮调用 this.setState()
时,我们会增加state.count
。我们将在整个页面中使用这个类的片段。
注意
您可能想知道为什么我们在这里使用计数器而不是更现实的例子。这是为了帮助我们专注于API,同时我们仍在使用 Hooks 迈出第一步。
Hooks 和 函数式组件
提醒一下,React 中的函数组件如下所示:
或者是这样的:
您可能以前将这些称为“无状态组件”。 我们现在介绍的这些组件将具有 React state(状态) 的能力,所以我们更喜欢称他为 “函数式组件”。
Hooks 在 classes(类) 内 不 起作用。 但是你可以使用它们来取代编写类。
什么是 Hook ?
我们的新示例首先从 React 导入 useState
Hook 开始:
什么是 Hook ? Hook是一种特殊函数,可让你 “接入” React 功能。 例如,useState
是一个 Hook,允许您将 React state(状态) 添加到函数式组件中。 我们稍后会学习其他的 Hooks。
我什么时候使用 Hook? 如果你编写一个函数式组件并意识到你需要为它添加一些 state(状态) ,那么之前你必须将它转换为一个 classes(类) 。 但是现在,您可以在现有函数式组件中使用 Hook 。 我们现在要做到这一点!
注意:
关于在何处可以使用 Hook 并且不能在组件中使用 Hook ,有一些特殊规则。 我们将在 Hooks 规则 中学习这些特殊规则。
声明一个 state(状态) 变量
在类中,我们通过在构造函数中将 this.state
设置为 { count: 0 }
来将 count
state(状态) 初始化为 0
:
在函数式组件中,我们没有 this
,所以我们不能分配或读取 this.state
。相反,我们可以直接在组件内部调用 useState
Hook:
调用 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 的作用,我们的例子应该更有说明意义:
我们声明一个名为 count
的 state(状态)变量,并将其设置为 0
。React 将记住它在重新渲染之间的当前值,并为我们的函数提供最新的值。如果我们想要更新当前 count
,我们可以调用 setCount
。
注意
您可能想知道:为什么
useState
没有命名为 createState
?“Create” 不是非常准确,因为 state(状态) 仅在我们组件第一次渲染时创建。 在下一次渲染期间,
useState
为我们提供了当前 state(状态) 。 否则它根本不会是 “state(状态)” ! Hook 名称总是以 use
开头也是有原因的。我们将在后面的 Hooks 规则 中了解。
读取 state(状态)
当我们想要在类中显示当前计数时,我们使用 this.state.count
读取:
在函数中,我们直接使用 count
读取:
更新 state(状态)
在类中,我们需要调用 this.setState()
来更新 count
状态:
在函数中,我们已经将 setCount
和 count
作为变量,因此我们不需要 this
:
概括
现在让我们用一行一行地回顾一下我们所学到的知识,并检查我们是否已经理解。
- 第1行:我们从 React import(导入)
useState
Hook。 它允许我们在一个函数组件中保持本地state(状态)。 - 第4行:在
Example
组件中,我们通过调用useState
Hook来声明一个新的 state(状态) 变量。它返回一对值,我们给它们命名。我们调用变量count
,因为它包含按钮单击次数。我们通过传递0
作为惟一的useState
参数,将其初始化为0
。它允许我们更新计数,因此我们将其命名为setCount
。 - 第9行:当用户点击时,我们使用新值调用
setCount
。 然后,React 将重新渲染 Example 组件,并将新count
值传递给它。
乍一看,似乎有很多东西需要考虑。别着急! 如果你对上面的解释中有困惑,再看一遍上面的代码,试着从头到尾读一遍。我们保证,一旦您试图“忘记” state(状态) 如何在 class(类) 中工作,并以全新的眼光看待这段代码,它就会有意义。
提示:方括号意味着什么?
当我们声明一个 state(状态) 变量时,您可能已经注意到方括号:
左侧的名称不是 React API 的一部分。您可以根据自己的需求 命名自己的 state(状态) 变量:
方括号语法其实是 JavaScript “数组解构” 语法。这意味着我们正在创建两个新变量 fruit
和setFruit
,其中 fruit
设置为 useState
是第一个返回值,setFruit
是第二个返回值。它相当于下面这段代码:
当我们使用 useState
声明一个 state(状态) 变量时,它返回一个对(pair) - 一个包含两个项元素的数组。第一项元素是当前值,第二项元素是允许我们更新第一项元素值的函数。使用 [0]
和 [1]
访问它们有点令人困惑,因为它们有特定的含义。这就是为什么我们使用数组解构的原因。
注意
您可能很好奇,React 是如何知道哪个组件对应哪个
useState
,因为我们没有将相关的任何内容传递给React。 我们将在FAQ部分回答 这个问题 和许多其他问题。
提示:使用多个 state(状态) 变量
将 state(状态) 变量 声明为一对 [something, setSomething]
也很方便,因为如果我们想使用多个状态变量,它可以为 不同 的 state(状态) 变量赋予不同的名称:
在上面的组件中,我们将 age
,fruit
和 todos
作为局部变量,我们可以单独更新它们:
您不必使用很多 state(状态) 变量。 状态变量可以很好地保存对象和数组,因此您仍然可以将相关数据组合在一起。 但是,与 class(类) 中的 this.setState
不同,更新状态变量总是替换它,而不是合并它。
我们 在FAQ中 提供了有关拆分状态变量的更多建议。
下一步
在这个页面上,我们了解了 React 提供的一个名为 useState
的 Hook 。 我们有时也会将其称为 “State(状态) Hook” 。 它允许我们将本地 state(状态) 添加到 React 函数式组件 - 这是我们第一次做到了!
我们还了解了 Hooks 的更多内容。 Hooks 是让您的函数式组件 “接入” React 功能的函数。 他们的名字总是以 use
开头,还有更多我们还没见过的 Hooks 。
现在让我们继续 学习下一个 Hook :useEffect。 它允许您在组件中执行副作用(side effects),类似于类中的生命周期方法。