useState这个hook主要用来获取和更新数据,useState 返回2个元素的数组
- 第一个是 state 的当前值
- 第二个是 state 的 setter 方法,调用时会触发 rerende
1.setState的常规使用
例如
import react, { useState } from 'react';
function hooker() {
const [count, setCount] = useState(0); // 这里左边定义了一个变量和一个改变这个变量的函数
// 右边通过这个hook钩子传入了一个初始值来赋值给这个变量
return (
<div>
<button @click={() => {
setCount(count+1)
}}></button>
</div>
)
}
2.setState中的 previous state
使用场景:当我们目前更新的state需要依赖state的上一个状态值的时候,需要使用previous state,此时setCount状态更新函数中的参数不再是一个值,而是一个函数参数,这个函数参数中的入参就是previous state。
import react, { useState } from 'react';
function hooker() {
const [count, setCount] = useState(0); // 这里左边定义了一个变量和一个改变这个变量的函数
// 右边通过这个hook钩子传入了一个初始值来赋值给这个变量
const addCount = () => {
for(let i = 0; i< 5; i++) {
setCount(count + 1)
}
}
return (
<div>
<button @click={ addCount }>直接加5</button>
</div>
)
}
我们期望的结果是点击button,count可以直接加5,因为我们在for循环中执行了5次setcount(count+1),那么第一次执行的时候setcount(count + 1),此时count变为2。然后又执行一次setcount(count+1),那么count执行count = count + 1 => 2 + 1 = 3,所以这样执行下去,count值就被加1执行了5次。但是事实真的是这样吗? 真实执行结果是:点击button,count最后值变为了2。
为什么?因为setCount更新方法是异步的。(考点:useState导出的更新函数是同步的还是异步的)
这里需要解决两个问题
2.1 useState导出的更新函数是同步的还是异步的?
2.2 如何解决button执行五次+1的操作?
针对第二个问题:setCount((previous) => previous + 1),即setcount函数参数为一个执行函数,它的函数参数为previous。使用 previousState 时,要使用 setter function 的方式,传参给 setState 方法。这样就能来确保拿到的是准确的之前的previous state。
如下:
import react, { useState } from 'react';
function hooker() {
const [count, setCount] = useState(0); // 这里左边定义了一个变量和一个改变这个变量的函数
// 右边通过这个hook钩子传入了一个初始值来赋值给这个变量
const addCount = () => {
for(let i = 0; i< 5; i++) {
setCount((previous) => previous + 1)
}
}
return (
<div>
<button @click={ addCount }>直接加5</button>
</div>
)
}
3.useState钩子的注意点
3.1 useState中的state数据类型为对象或者数组的时候
(1)对象
这里我们想只更改对象的某个属性,而setName函数在传入更新对象参数的时候,需要传入整个参数,不能只传入某个更新值,这样会报错。所以需要在setName函数中需要将name进行解构赋值,放在一个新的对象中,再加入更新的属性即可。
import React, { useState } from 'react'
function HookCounter() {
const [name, setName] = useState({
firstName: '',
lastName: ''
})
return (
<form>
<input
type="text"
value={name.firstName}
onChange={e => {
setName({
firstName: e.target.value
})
}}
/>
<input
type="text"
value={name.lastName}
onChange={e => {
setName({
lastName: e.target.value
})
}}
/>
<h2>Your first name is {name.firstName}</h2>
<h2>Your last name is {name.lastName}</h2>
</form>
)
}
export default HookCounterimport React, { useState } from 'react'
所以正确更新对象的方式是:手动合并对象属性
import React, { useState } from 'react'
function HookCounter() {
const [name, setName] = useState({
firstName: '',
lastName: ''
})
return (
<form>
<input
type="text"
value={name.firstName}
onChange={e => {
setName({
...name, // 将state进行解构赋值
firstName: e.target.value // 新的属性会覆盖之前name中的对应属性
})
}}
/>
<input
type="text"
value={name.lastName}
onChange={e => {
setName({
...name,
lastName: e.target.value
})
}}
/>
<h2>Your first name is {name.firstName}</h2>
<h2>Your last name is {name.lastName}</h2>
<h2>{JSON.stringify(name)}</h2>
</form>
)
}
export default HookCounter
(2)数组
import React, { useState } from 'react'
interface ItemType {
id: number
value: number
}
function UseStateWithArray() {
const [items, setItems] = useState<ItemType[]>([])
const addItem = () => {
setItems([
...items, // 这里对数组进行解构赋值
{ // 这里是进行相加的增加
id: items.length,
value: Math.ceil(Math.random() * 10)
}
])
}
return (
<div>
<button onClick={addItem}>add a number</button>
<ul>
{
items.length > 0 && items.map((item: ItemType) => (
<li key={item.id}>{item.value}</li>
))
}
</ul>
</div>
)
}
export default UseStateWithArray