React中有很有Hooks还可以自定义Hooks,为什么我要分享这三个呢,因为掌握这三个Hooks就可以在日常的业务中解决80%的问题.就像在vue中学习那么多的生命周期,最后发现写了100个组件中,其中90个都只用到了mounted.
useState让函数组件拥有自己的状态
我们先用一个添加的小例子来感受和认识一下userState。
拿我个人的学习历程来说吧,在最开始接触Hooks语法时,最令我费解的是这种解构式,声明状态的方式,如果靠我们的记忆去记住这个语法,它是没有任何难度的,可以说是so easy,因为相对于类组件一个状态的,声明,使用,改变,useState都是更简洁的做了同样的事情.
funVsclass
声明:无论是字符串,数组,对象,布尔值,都是一对一的把初始值传给useState就可以了,而不是统一写在this.state中
使用:在使用状态时直接拿过来用,就跟使用普通变量是一样的,再也不用解构this.state。
改变:解构出来的第二个参数是一个函数,这个函数接受的参数就是这个state最新的值,其实第二个参数的名字叫什么都可以,都不会给你报错,只是大家都约定set+'变量名字'。 setCount(newValue) 每当执行完set函数,就会调用render(),进行视图更新
我们分别声明一个state和一个普通变量,并在控制台打印一下看看结果
const [add, setAdd] = useState(0)
let count = 0
const handleAdd = () => {
setAdd(add + 1)
count += 1
}
console.log(add, '========state')
console.log(count, '========普通变量')
return (
......
)
从这个例子中我们可以看出来set函数的执行会让函数组件从新执行,count每次初始化都会被赋值0,这个是可以理解的,但不是我们想要的.正常情况我们解构出来这个add每次被初始化后也应该是0才对.但是useState()却保留了它最新的状态(也就是我们改变后的值).
我们可以自己写一个useState()函数去看看他都做了那些事情,
1.接受一个初始值
2.内部有一个函数去更新状态
3.要有一个容器保存最新的值
我们,根据这个思路来实现一个精简版的useState函数(以下代码仅表达思路)
let container = [] {1}
let index = 0 {2}
function useState(intValue){
container[index] = container[index] || intValue
function setState(newValue){
container[index] = newValue
//....让视图更新逻辑
}
return [container[index++],setState] {3}
}
{1}:这个容器在函数外部他就不会受到每次useState函数执行的影响,
{2}:同时要有一个下标去记录每一个状态的位置
{3}:第一个state的声明这里读取的仍然是container[0],index在下一次使用才是1
const [count setCount] = useState("0")
聪明的小伙伴已经看出来 这是利用了闭包来实现状态的缓存(闭包是一个很大的话题,今天主要说Hooks)。
当看懂上面的代码 我们再用useState去声明状态时,肯定不是靠语法的记忆,而是知道它内部大概的样子解构出来也就会很舒服。
需要注意的是,我们声明状态的时候一定要在函数的最顶层,不要在,if{},function{}里去声明,从上面的代码可以看出,container容器是根据状态的声明的顺序进行缓存的,读取的时候也是按照相应的顺序,如果在某些条件成立或者某个函数被调用,再去声明顺序会被打乱的.
useRef 一个全局的变量[以下简称Ref]
useRef和useState可以说是一对孪生兄弟
需要注意的是useRef声明的变量,需要通过.current才能访问它的值(是不是跟vue3中的某个语法好像...).
我们同时使用ref,state声明变量,对他俩++并在页面展示对应值的变化(同时可以对比一下 与上面普通变量的区别)
...这,Ref好像跟state是一样的呀,react怎么会给出两个相同的Hooks呢。
我们单独对Ref进行++再试一次
很明显它一动不动
由此我们可以知道,Ref也是有状态缓存的作用,每次组件初始化不会影响他的值,但是他的改变不会引起当前组件的重新执行,自然视图也不会更新.这就是他与state的区别.
当我们需要获取组件实例,声明跟视图更新无关的变量时就可以用Ref去声明.
useEffect它是一个遥控器[以下简称ect]
ect的使用方式非常简单
useEffect(()=>{
//我会在页面初始化完成执行一次
//页面每更新一次我就会执行一次
})
useEffect(()=>{
//我只会在页面初始化完成执行一次
//和componentDidMount vue中 mounted 相似
},[])
useEffect(()=>{
//我会在页面初始化完成执行一次
//当a和b的值发生变化我也会执行一次
**a,b的值必须是props或者state,否择我不会执行**
},[a,b])
useEffect(()=>{
return ()=>{
//我在什么时候执行呢?
}
},[a,b])
ect这个函数他是正常执行的,它相当于一个遥控器,他来控制他的第一个参数什么时候执行,怎么去控制呢? 用它的第二个参数去控制.
假如我们在第一个参数中返回一个fn那么这个fn是什么时候执行呢?(下面简称Rfn)
从这个例子中可以看出Rfn的执行时机是,下一次fn(第一个参数)执行之前,并且Rfn中的state是旧值,fn中永远都是最新的state,也就是所谓的把他当作componentWillUnmount钩子来使用,其实还是不一样的。我们可以用它来做防抖,当最新的fn执行时,我们在Rfn中 把旧的fn清除,他的妙用还有很多,小伙伴们可以去发掘下。
在我入门react的时候 差点被劝返的就是生命周期,对新手来说不是那么的友好.但是 在函数式组件中,你只要用好ect就够了,它可以说是一个人干了好几个人的活,非常的nice。