Hook简介
- hook是react16.8之后出现的
组件分为
- 无状态组件(函数组件)
- 类组件
类组件中的麻烦
- this指向的问题(bind、箭头函数的形式)
- 繁琐的生命周期(需要理解记忆)
- 其它问题后面结合代码说
Hook 专门用于增强函数的功能(不能在类组件中使用),使之理论上可以成为类组件的替代品
- 官方强调:没有必要去更改已经完成的类组件,官方没有计划取消类组件,只是鼓励使用类组件
- hook(钩子)本质上是一个函数(命名总是已use开头),改函数可以挂载任何功能
- 不同的hook有不同的功能
Hook种类
- useState、useEffect等后面笔记补充
useState
- 用于在函数组件中使用状态
- useState函数有一个参数,这个参数的值表示状态的默认值
- 无值默认 undefined
- 返回值是一个数组,该数组包含2项
- 第一项: 当前状态的值
- 第二项: 改变状态的函数
- 一个函数组件可以又多个状态,这种做法非常有利于横向切关注点
import React, { useState } from 'react'
export default function StateHook() {
const [num, setNum] = useState(0)
const [isShow, setShow] = useState(true)
return (
<div>
<div style={{ display: isShow ? 'block' : 'none' }}>
<button onClick={() => setNum(num - 1)}>-</button>
<span>{num}</span>
<button onClick={() => setNum(num + 1)}>+</button>
</div>
<button onClick={() => setShow(!isShow)}>显示/隐藏</button>
</div>
)
}
state 原理图
- 函数运行有一个特点,内部的代码会全部运行,怎么保持住状态的
- 原理图如下,对应上面的代码
注意细节
- 多多少少跟它的原理有关系
- useState最好写在函数的起始位置,便于阅读
- useState严禁出现在代码块(判断、循环)中
- useState返回的函数(数组的第二项引用不变,节约内存空间)
- 使用函数改变数据,如果数据和之前的数据完全相等(使用Object.is比较),不会导致重新渲染,以达到优化效率的优点
- 使用函数改变数据,传入的值不会和原来的数据合并,而是直接替换
- 逻辑不是一块(状态之间没有必然联系)的数据建议切分,不要写在一块
import React, { useState } from 'react'
export default function StateHook() {
const [data, setData] = useState({
x: 1,
y: 1
})
return (
<div>
<div>x: {data.x} --- y: {data.y}</div>
<button onClick={() => {
setData({
...data,
x: data.x + 1
})
}}>X</button>
<button onClick={() => {
setData({
...data,
y: data.y + 1
})
}}>Y</button>
</div>
)
}
- 如果要实现强制刷新组件
- 7.1 类组件中: 使用this.forceUpdate()函数(不推荐),不会运行shouldComponentUpdate
- 7.2 函数组件: 可以使用空对象,因为地址不一样了
function XX () {
const [,forUpdate] = useState({})
return (
<>
<button onClick={() => {
forUpdate({})
}}>强制刷新</button>
</>
)
}
- 和类组件一样,函数组件中改变状态可能是异步的(在DOM事件中),多个状态变化会合并以提高效率,此时不能信任之前的状态,而是使用回调函数的方式
import React, { useState } from 'react'
export default function StateHook() {
console.log('render !!!')
const [num, setNum] = useState(0)
return (
<div>
<div>
<button onClick={() => {
setNum(num - 1)
setNum(num - 1)
}}>-</button>
<span>{num}</span>
<button onClick={() => {
setNum(num + 1)// 不会立即变化,事件运行完成之后一起变化
setNum(num + 1)// 此时 n 的值还是 0 -> 1
}}>+</button>
//正确做法如下
<button onClick={() => {
setNum((preN) => preN + 1)// 传入函数,在事件完成之后统一运行 -> 1
setNum((preN) => preN + 1)// -> 2
}}></button>
</div>
</div>
)
}