React的Hook之useState

我们在写Vue时,组件从挂载到卸载有初始化前后更新前后卸载前后这样的三种类型的生命周期,当然,在这里面,还有更细的分类,这里就不再一一例举了。作为目前前端主流框架的React,也有如此类似的生命周期。

试想一下,这么多的状态,如果我要获取一个值,时而把它清空,时而有需要加载,时而更新,想想头都大了,有没有一种方法,能够智能的管理这个值的去留问题呢?

欸!还真有,这个就是今天要介绍的React中好玩的Hook

什么是Hook呢?

我们先来看看官方的定义:

Hook 是一些可以让你在函数组件里“钩入” 生命周期等特性的函数。

Hook 使你在无需修改组件结构的情况下复用状态逻辑。 这使得在组件间或社区内共享 Hook 变得更便捷。

不妨我们先从代码入手,来看看什么是hook。在React中有两种组件,一种是函数组件,另一种则是类组件。组件内部当然是需要自身使用的值,那么我们可以把这些值叫做state。我们先来看一下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//不使用hook的类组件
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>
);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//使用hook的函数组件
import React, { useState } from 'react';
function Example() {
// 声明一个叫 "count" 的 state 变量
const [count, setCount] = useState(0);

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

这两个组件实现的功能都是点击按钮实现数据改变。但我们可以看出,使用hook的函数组件写的更加优雅

在函数组件中,我们没有 this,所以我们不分配或读取 this.state,直接在组件中调用 useState 进行数据处理。这样避免了烦人的this指向问题。

写过react的都知道,在类组件中,写的函数处理稍有不慎,就会出现一下错误:即找不到是谁调用的。

image-20220123164009541

当然,这里并不是说类组件一无是处了,该有用的时候还是有用的,这里就不作展开。

Hook 之 useState

从上面的代码可以看出,在函数组件里,我们仅仅只需要应用Hook,就能够把繁琐的数据处理步骤给简化,那么在React中,我们通常使用useState这个Hook进行数据处理。

useState 方法里面唯一的参数就是初始 state。不同于 class 的是,我们可以按照需要使用数字字符串甚至是对象对其进行赋值。在上面的示例中,因为只需使数字来记录用户点击次数,所以我们传了 0 作为变量的初始 state

使用useState的语法很简单,我们只需要定义一个state的名字,并给他赋初始值,同时,还要有一个处理这个state的方法名字。代码如下:

1
const [value,setValue] = useState('CHUYUXUAN');

这种写法其实是JavaScript 中的一个语法,我们称之为数组解构。它意味着我们同时创建了 valueseValue 两个变量,vaule 的值为 useState 返回的第一个值,setValue 是返回的第二个值。它等价于下面的代码:

1
2
3
var valueStateVariable = useState('CHUYUXUAN'); // 返回一个有两个元素的数组
var value = valueStateVariable[0]; // 数组里的第一个值
var setValue = valueStateVariable[1]; // 数组里的第二个值

使用 useState 定义 state 变量时候,它返回一个就如上面所等价的一样,有两个值的数组。但是,如果我们用数组来弄,【0】【1】这样的标注,会让我们觉得很困惑,所以,在React社区,就默认这种写法了。

上面我们有说到过,定义state的数据类型,可以有很多种,例如:

1
2
3
const [age, setAge] = useState(42); //数字
const [fruit, setFruit] = useState('banana');//字符串
const [todos, setTodos] = useState([{ text: '学习 Hook' }]);//对象

在官方文档中有这么一句话:

You don’t have to use many state variables. State variables can hold objects and arrays just fine, so you can still group related data together. However, unlike this.setState in a class, updating a state variable always replaces it instead of merging it.

使用useState,在render的时候,他并不像 class 中的 this.setState,更新state的时候去替换它原本身的值,不管这个值是不是没变。而useState会检测它的变化,如果改变则更改,不变则保持,这个叫做合并。