06-类组件的生命周期(非常重要)
# 一,类组件的生命周期(非常重要)
# 1,constructor(装载)
vue组件的生命周期,有些并不重要,基本上用不到,但是React的生命周期都非常重要,没有多余的,关于生命周期有非常多的面试题。
只有类组件才会有生命周期钩子函数,函数式组件没有生命周期钩子的函数的。
生命周期函数很多,我们需要掌握6个:
- 装载阶段(3个):constructor, render, componentDidMount
- 更新阶段(2个):render,componentDidUpdate
- 卸载阶段(1个):componentWillUnmount
图示:
现在就一个个学习,先学习constructor,代码如下:
在constructor中,可以完全this的绑定如下:
昨天我们说了两种解决办法:
在官方文档中,还有一种解决办法,就是在constructor中进行this绑定,如下:
在constructor中有一个props,这个props是用来接收父传递的数据的,props的数据流和state的数据流必须独立。下面的代码是不规范的,如下:
在constructor中,不能调用setState方法,如下:
在constructor中,不能调用接口,不能进行DOM操作,不能开定时器... 一切和业务相关的代码都不能写在constructor钩子函数中。
总结在constructor中,可以做什么:
- 定义状态
- 绑定方法的this
# 2,render(装载)
作用:用于返回组件的视图结构,这个结构在vue叫模板,在react中叫jsx。它的背后是生成一棵Fiber树,在vue中叫虚拟DOM,在React叫Fiber树,早期的React也是使用的虚拟DOM。
在render函数中,不能调用setState,如下:
上面的写法是,你直接调用了setState,有时候,你会间接地调用setState,如下:
浏览器死循环了,如下:
render是一个函数,这个函数返回一个jsx,jsx叫jsx元素,本质是一个对象,创建jsx元素有2种方法,一种是直接使用jsx,另外一种是React.creeateEleement。也就说,调用render函数,会生成棵Fiber树,类似于Vue中的虚拟DOM,这个Fiber树是双向链表结构。生成这课Fiber树的过程是异步的,生成的过程是可以中断,能不能中断是看浏览器忙不忙,如果浏览器比较忙,就可能中断,等待浏览器不忙时,会继续生成,直到Fiber树创建完成。然后会进行协调运算,这个协调运算类似于Vue中的Diff运算,也就是一棵老的Fiber树和一棵新的Fiber树进行对比运算。运算对比后,就会进入到commmit提交阶段,一次性提交Fiber更新DOM。
# 3,componentDidMount(装载)
类似于vue中的mounted,表示页面第一次渲染完成。在这个钩子函数中可以做什么?
- 调用接口
- 开定时器
- DOM操作
- 编写业务逻辑
代码如下:
# 4,render(更新)
什么时候进入到更新阶段,如下:
代码如下:
# 5,componentDidUpdate(更新)
相当于Vue中的updated,表示页面再次渲染成功。
监听器是用来监听数据是否变化,updated表示数据变化了,会执行updated,也就是说数据变化了,在updated也可以监听到了。要监听数据变化,在vue中,使用监听器比使用updated更方便。在react中是没有监听器的概念的,在React中实现类似于Vue的监听器的功能,需要使用compoentDidUpdate钩子函数了。
上代码:
如果不使用componentDidUpdate,还有没有办法实现类似于Vue中的监听器?
答:this.setState({}/fn, callback) 利用callback也可以感知到数据变化了。推荐使用componentDidUpdate。因为多个setState会合并,合并后,callback也会出问题。代码如下:
在componetDidUpdate中,尝试调用setState,如下:
你要想在componentDidUpdate中调用setState,需要给出一个出口,不给出口,直接爆栈了,给出出口,如下:
使用定时器把setState包起来如下:
强调一下,React实现Vue中的监听器。Vue听监听器写法如下:
watch: {
page() {
axios.then(res => {
this.list = res.list;
})
}
}
在Vue中如果不使用watch, 可以使用updated代替。 但是在React没有watch, 只能使用componentDidUpdate来实现, 或使用setState中的callback来实现。
2
3
4
5
6
7
8
9
num变化了,我需要监听到num变化了,如下:
总结:
- componentDidUpdate中可以调用setState,但是必须给出出口(终止条件),否则会产生死循环,循环到一定次数就会报错。
- componentDidUpdate可以模拟vue中的监听器,特别需要注意终止条件。
- 除了使用componentDidUpdate实现监听器之外,还可以使用this.setState中的callback来实现,不建议使用,因为setState会合并,callback容易出问题。
# 6,componentWillUnmount(卸载)
类似于Vue中的beforeDestroy,表示组件即将销毁。在这里我们可以:
- 清缓存
- 清除定时器
- 关闭长连接
- 销毁DOM元素
- ....
# 7,shouldComponentUpdate(了解)
它是控制更新阶段的开关,说白了,就是来控制是否更新,当返回true就正常更新,当返回false时就不更新。
在项目中用的不多,是官方提供的一种性能优化方案。
代码如下:
默认情况下,没有写的话,就是返回true,看一下state参数,如下:
shouldComponentUpdate,返回true时,正常更新,返回false时,不执行更新阶段。注意细:
- 当执行forceUpdate时,会绕过shouldComponentUpdate方法,一定会进入到更新阶段。
- shouldComponentUpdate,可以使用PureCompoentf替代
为什么要使用这个开关呢?
答:组件中有很多状态,有些状态会参与到界面刷新,也就是说有些状态变了,需要更新页面。但是还有一些状态是不参与到界面更新,也就是状态变了,不需要更新页面的,此时就体现出开关的重要性了。参与页面更新的状态,状态变化了,在showCompoentUpdate中返回true,正常更新。如果没有参与页面刷新的状态变化了,在shouldCompoentUpdate中返回false,就需要再次调用render。这样,就会少生成一次Fiber树。这个钩子函数是用来性能调优的,可以阻塞掉那些不参与视图渲染的状态更新导致的Fiber生成。
React组件渲染(更新)流程,由两个阶段组成的,一个叫render阶段,一个叫commit阶段,如下:
render阶段:
- 目标是生成Fiber树,这个过程是异步的,是可中断,并且不会执行任何副作用。到底中断与否,看的是浏览器主线程的忙不忙。
commit阶段:
- 目的是把协调运算的结果,一次性提交渲染或更新真实DOM。这个过程在V18之前是不可中断的,在V18中是可以人为中断的。