学会三个这三个API解决React中80%的业务 useState,useEffect,useRef

3,083 阅读5分钟

React中有很有Hooks还可以自定义Hooks,为什么我要分享这三个呢,因为掌握这三个Hooks就可以在日常的业务中解决80%的问题.就像在vue中学习那么多的生命周期,最后发现写了100个组件中,其中90个都只用到了mounted.

useState让函数组件拥有自己的状态

我们先用一个添加的小例子来感受和认识一下userState。

add.gif

add.png

拿我个人的学习历程来说吧,在最开始接触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 (
      ......
  )


diff.gif

从这个例子中我们可以看出来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声明变量,对他俩++并在页面展示对应值的变化(同时可以对比一下 与上面普通变量的区别)

refA.png

diffRef.gif

...这,Ref好像跟state是一样的呀,react怎么会给出两个相同的Hooks呢。

我们单独对Ref进行++再试一次

diffRef2.gif

很明显它一动不动

由此我们可以知道,Ref也是有状态缓存的作用,每次组件初始化不会影响他的值,但是他的改变不会引起当前组件的重新执行,自然视图也不会更新.这就是他与state的区别.

当我们需要获取组件实例,声明跟视图更新无关的变量时就可以用Ref去声明.

useEffect它是一个遥控器[以下简称ect]

ect的使用方式非常简单

useEffect(()=>{

//我会在页面初始化完成执行一次
//页面每更新一次我就会执行一次
})

useEffect(()=>{

//我只会在页面初始化完成执行一次
//和componentDidMount vue中 mounted 相似
},[])

useEffect(()=>{

//我会在页面初始化完成执行一次
//当a和b的值发生变化我也会执行一次
**a,b的值必须是props或者state,否择我不会执行**
},[a,b])

useEffect(()=>{

 return ()=>{
 //我在什么时候执行呢?
 }
},[a,b])

effect.png

ect这个函数他是正常执行的,它相当于一个遥控器,他来控制他的第一个参数什么时候执行,怎么去控制呢? 用它的第二个参数去控制.

假如我们在第一个参数中返回一个fn那么这个fn是什么时候执行呢?(下面简称Rfn)

sum.png

sj.gif

从这个例子中可以看出Rfn的执行时机是,下一次fn(第一个参数)执行之前,并且Rfn中的state是旧值,fn中永远都是最新的state,也就是所谓的把他当作componentWillUnmount钩子来使用,其实还是不一样的。我们可以用它来做防抖,当最新的fn执行时,我们在Rfn中 把旧的fn清除,他的妙用还有很多,小伙伴们可以去发掘下。

在我入门react的时候 差点被劝返的就是生命周期,对新手来说不是那么的友好.但是 在函数式组件中,你只要用好ect就够了,它可以说是一个人干了好几个人的活,非常的nice。