这是我参与11月更文挑战的第8天,活动详情查看:2021最后一次更文挑战
上一篇文章我们学习了React Hooks的优点,解决了类组件的部分问题,还学习了useState的基本使用方法,在这一篇文章里我们学习一下一个新的React Hook——useEffect
一、useEffect剖析
1、 在这里我们先了解一下effect(副作用),指的是没有用于发生在数据——视图转换过程中的逻辑,比如数据请求、访问DOM元素、缓存操作、绑定/取消事件监听、订阅、设置定时器等等非数据——视图逻辑中的操作,均为副作用
2、useEffect的功能:
useEffect为函数式组件提供了操作副作用的能力(原本的函数式组件内进行副作用操作是不被允许的,这样有可能会破坏数据界面一致性),useEffect将React的componentDidMount、componentDidUpdate、componentWillUnmount的三个生命周期进行了整合,函数式组件可以通过useEffect钩子执行在类组件中这三个生命周期的相同逻辑
React Hooks是可以重复使用且相互独立的,因此我们在编写逻辑时,可以对每个副作用操作绑定一个useEffect钩子,这样就不需要将多个副作用操作写在一个生命周期里了
3、useEffect的使用
-
useEffect可以传入两个参数,第一个参数是一个函数,用于进行副作用操作;第二个参数则是一个数组,数组中的元素是对副作用操作执行的一个条件,当数组内元素对应的状态更新时,才进行该副作用的执行 -
基本使用:使用
useEffect:将函数作为参数传入useEffect钩子函数中,这一个函数内的逻辑则是即将进行的副作用function Title() { const [title, setTitle] = useState("Jue Jin"); useEffect(()=>{ document.title = `Welcome to ${title} !`; }) } -
我们还可以通过限制条件指定触发副作用的状态变量:
function Title() { const [title, setTitle] = useState("Jue Jin"); const [number, setNumber] = useState(1); //仅在title发生变化后才执行副作用 useEffect(()=>{ document.title = `Welcome to ${title}`; },[title]) return ( <div> <h1>{number}</h1> <button onClick={()=>{ setNumber(number=>number+1) }}> + 1 </button> </div> ) } -
useEffect绑定后会在每次渲染后对副作用逻辑进行一次处理,如果想清除副作用,有两种方法,第一种是传入一个新的函数给useEffect,另一个则是向useEffect的第二个参数传入一个空数组。当第二个参数传入的是空数组时,则说明副作用不依赖于某个状态的更新,则只会调用在组件的挂载流程(即只运行一次),不会在更新阶段进行调用//方法一:返回一个新函数 //useEffect在执行副作用前,会调用上一次返回的函数 useEffect(()=>{ if(!destroy){ document.title = `Welcome to ${title}`; }else{ return ()=>{ console.log("useEffect destroyed"); } } }) //方法二:第二个参数传入空数组 useEffect(()=>{ document.title = `Welcome to ${title}`; },[]) -
我们还可以通过使用多个
useEffect来将多个副作用操作分离开,不必像类组件那样麻烦地堆在同一个生命周期中
4、注意事项
其中要注意,正常的useEffect传入的函数(也就是副作用的相关操作)在每次视图的渲染后都会被调用(初次渲染+更新渲染),这就是上文所说的对componentDidMount、componentDidUpdate的整合。
另外,componentDidMount与componentDidUpdate中的代码是同步执行的,是会阻塞浏览器视图更新的,而useEffect中的副作用是异步的,不会阻塞浏览器进行视图更新,能够满足基本的副作用安排需求
二、useLayoutEffect
上面又说到useEffect中的副作用是异步的,不会阻塞浏览器进行视图更新,但是如果我想同步进行呢?这就可以用到useLayoutEffect了(不过一般使用useEffect就够了),下面放一张浏览器渲染的流程图:
抛开机制,使用方法与useEffect没有什么差别,其中:
useEffect是在浏览器渲染完毕后才调用副作用的useLayoutEffect会在Layout(DOM与CSSOM合并、排列)之后,Painting(绘制)之前执行副作用useLayoutEffect会在DOM更新后同步调用副作用- 特殊用法:我们可以使用
useLayoutEffect来获取DOM元素相关信息,做了相应处理以后同步触发渲染(即进行测量等操作)