前言
本篇文章我们来系统的讲解React组件的生命周期。React随着版本的不断提升,组件的生命周期也在不断地改版和升级。本篇文章以React 17为例,讲解最新版React的组件生命周期,同时阐述各个生命周期所执行的生命周期函数。
一、React组件的生命周期
React 17将组件的生命周期分为以下三个阶段:
- 组件的挂载阶段(Mounting)
- 组件的更新阶段(Updating)
- 组件的卸载阶段(Unmounting)
二、React组件的挂载阶段
在React中,将组件第一次插入至DOM树中渲染的过程称之为“挂载”。挂载阶段要完成组件状态的初始化、创建API调用请求、启动或停止计时器、操作已渲染的DOM、初始化第三方脚本库等工作。React组件挂载阶段涉及到以下四个生命周期函数。
- constructor()
- getDerivedStateFromProps()
- render()
- componentDimMount()
1、constructor()构造函数
从原理上来讲,constructor()构造函数并不是一个生命周期函数,只是当组件挂载时,构造函数永远是第一个被触发的。构造函数的主要功能是初始化组件状态,即为state区设置初始化数据。
构造函数的格式如下所示。
class Comp extends react.Component{
constructor(props){
super(props);
this.state={
// 初始化React组件状态
}
}
}
2、getDerivedStateFromProps()生命周期函数
该函数是一个静态函数,使用时必须声明static关键字,且不能在其内部使用this关键字。同时使用时有两个参数:nextProps、prevState,分别用来表示父组件传递过来的参数对象和组件的state区数据对象。该生命周期函数在使用时有如下规定。
- 组件必须在constructor()构造函数中设置state区,否则该函数会报错。
- 该生命周期函数必须返回一个对象,或者返回null。
从这个生命周期函数的名字中就可以看出,它的功能是从props中获取state,即利用父组件传递过来的props属性来更新state数据。
例1:父组件调用子组件,并向Comp传递title和content两个参数。
父组件核心代码:
子组件代码:
class Comp extends React.Component{
constructor(props){
super(props);
this.state={
ca:15,
cb:20
}
console.log(this.state);
}
static getDerviedStateFromProps(nextProps,prevState){
console.log(nextProps);
console.log(prevState);
const {title,content} = nextProps;
return {
title,content
}
}
}
在上述代码中,组件Comp挂载阶段,先执行构造函数constructor(),再执行静态函数getDerviedStateFromProps()。所以在构造函数中输出this.state,结果为:{ca:15,cb:20}。
静态函数getDerviedStateFromProps()中nextProps参数是父组件向子组件传递的数据构成的对象,所以输出nextProps的结果为:{title:“组件挂载”,content:“将组件第一次插入至DOM树中渲染”}。
静态函数getDerviedStateFromProps()中返回的对象都是要加入到组件的state状态中的,所以父组件向子组件传递的title数据和content数据也会变为state状态区中的一部分。
3、render()渲染函数
render()渲染函数是React组件的必备函数,没有该函数React组件会报错。该函数用来返回使用JSX语法实现的组件内容,包括HTML标记对和JavaScript业务流程。在例1中,如果在render()函数中输出this.state,因为getDerviedStateFromProps()函数在render()函数之前执行,所以此时输出的结果为:{ca:15,cb:20,title:“组件挂载”, content:“将组件第一次插入至DOM树中渲染”}。
4、componentDidMount()生命周期函数
该函数是组件挂载阶段最后一个执行的生命周期函数,会在组件挂载成功且渲染完毕之后触发。项目开发过程中,多在该函数中调取API数据,例如使用Fetch、Axios技术从后台获取组件使用的数据。
三、React组件的更新阶段
在React中,将组件重新渲染的过程称之为“更新”。当组件的state数据发生变化或从父组件接收到新的属性时进入到组件的更新阶段,即调用this.setState()方法时,组件会启动更新阶段。React组件更新阶段涉及到以下五个生命周期函数。
- getDerviedStateFromProps()
- shouldComponentUpdate()
- render()
- getSnapshotBeforeUpdate()
- componentDidUpdate()
首先,要重点声明。上述函数都是在组件更新时触发的生命周期函数,即一旦执行了this.state()方法,上述函数就会依次执行一遍。也就是说,如果在上述函数中调用了this.state()方法,将会使更新生命周期引发无限递归循环,从而导致堆栈溢出。因此上述函数中不得调用this.state()方法。render()函数中元素的事件函数除外,因为事件函数虽然书写在render()函数内部,但是并不自动执行,因此不会导致堆栈溢出。
1、shouldComponentUpdate()生命周期函数
该生命周期函数有两个参数:nextProps、prevState,分别用来表示父组件传递过来的参数对象和组件的state区数据对象。
该生命周期函数被称为更新阶段的“门卫”,在使用时必须返回一个逻辑值,以表示后面的更新生命周期函数是否继续执行。
- 返回true,表示继续执行组件的更新生命周期函数。
- 返回false,表示不再继续执行组件的更新生命周期函数。
这里需要注意,该生命周期函数返回false,只表示不再继续执行后面的生命周期函数,触发更新声明周期启动的this.setState()方法依然会成功执行。
例2:当更新state区中的title数据时,判断父组件传递的title是否与更新后的title一致,如一致就停止执行生命周期过程;如不一致则继续执行生命周期过程。
class Comp extends Component {
constructor(props){
super(props);
this.state={
ca:15,
cb:20
};
}
shouldComponentUpdate(nextProps,prevState){
if(nextProps.title!==prevState.title){
return true;
}
return false;
}
btnClick(){
this.setState({
title:"你好"
})
}
render() {
console.log("Render函数");
console.log(this.state);
return (
我是Comp组件
);
}
}
2、getSnapshotBeforeUpdate()生命周期函数
该生命周期函数在组件的更新阶段,在render()函数之后,组件DOM渲染之前触发。具备以下两个参数。
- prevProps:依然表示父组件向子组件传递的数据。
- prevState:依然表示state区中的数据。
该生命周期函数在使用时有如下两个规定:
- 必须配合componentDidUpdate()生命周期函数共同使用。
- 必须返回一个值,该值将作为componentDidUpdate()生命周期函数的第三个参数。
3、componentDidUpdate()生命周期函数
该生命周期函数在组件更新完成后触发,其语法格式如下所示。
componentDidUpdate(prevProps,prevState,snapshot){}
四、React组件的卸载阶段
在React中,从DOM树中删除组件的过程称之为“卸载”。该生命周期只有一个生命周期函数。
- componentWillUnmount()
可以在该生命周期函数中清除timer计时器以及在componentDidMount()生命周期函数中声明的变量。
总结
本文是React系列教程的第八篇文章,主要为大家讲解了React 17中组件的生命周期与各个生命周期的函数。整体来说,生命周期函数的执行可以用下图来进行说明。
关于作者
小海前端,具有18年Web项目开发和前后台培训经验,在前端领域著有较为系统的培训教材,对Vue.js、微信小程序开发、uniApp、React等全栈开发领域都有较为深的造诣。入住Segmentfault,希望能够更多的结识Web开发领域的同仁,将Web开发大力的进行普及。同时也愿意与大家进行深入的技术研讨和商业合作。