在组件创建、组件属性更新、组件被销毁的过程中,总是伴随着各种各样的函数执行,这些在组件特定时期,被触发执行的函数,统称为组件的生命周期函数。
组件的生命周期一共有三个阶段:挂载、更新、卸载。
1.挂载就是组件初始化的时候调用的方法,也就是说,这些方法在组件的生命中只能执行一次;
2.更新就是组件的某部分属性或者状态发生改变,就会去执行的方法,在组件的生命中既可以执行0次,也可以执行多次;
3.卸载就是在组件被销毁的时候执行的方法,执行之后就意味着组件的生命到头了,因此,在组件的生命中也只能执行一次。
生命周期的方法:
1.挂载
当组件实例被创建并插入 DOM 中时,其生命周期调用顺序如下
- constructor()
- static getDerivedStateFromProps()
- render()
- componentWillMount() //React17中已过时
- componentDidMount()
其中componentWillMount在React17中已经是一个过时的生命周期函数,新的代码的避免使用。
constructor 构造函数
在构造函数中,主要进行的是定义props、初始化内部的state、给一些事件处理方法绑定this。
定义props:
constructor(props) {
super(props); //定义this.props
this.state = {name: "lifecycle"}; //给this.state赋值来初始化内部的state
this.handler = this.handler.bind(this); //由于在JavaScript中,class的方法默认不会绑定 this,给类中的方法绑定this
}
static getDerivedStateFromProps
这个生命周期的方法,会在render之前被调用,其返回一个对象来更新state,返回null则不更新state。
//life-cycle.js
import React from "react";
class LifeCycle extends React.Component {
constructor(props) {
super(props);
this.state = {name: "lifecycle"};
}
static getDerivedStateFromProps(nextProps, prevState) {
console.log('getDerivedStateFromProps');
const {name} = nextProps;
// 当传入的type发生变化的时候,更新state
if (name !== prevState.type) {
return {
name,
};
}
// 否则,对于state不进行任何操作
return null;
}
render() {
console.log("render");
return <h1>{this.state.name}</h1>
}
}
export default LifeCycle;
//index.js
import React from 'react';
import ReactDOM from 'react-dom';
import LifeCycle from "./life-cycle";
ReactDOM.render(
<LifeCycle name={"life"}/>,
document.getElementById('root')
);
结果我们看到,在render之前调用了这个方法同时,使得设置的默认"lifecycle"被这个方法改成了和props一样。
render
render生命周期是class组件中唯一一个必须实现的方法;
在调用的时候,会检测this.props和this.state,返回本地的虚拟DOM组件,或者自定的符合组件;也可以返回null或者false来表示不需要渲染任何东西;
render的方法应该是纯粹的;就意味着在render中不应该调用setState,每次调用都返回相同用的结果,不读写DOM节点的信息,也不和浏览器交互。
componentDidMount
在初始化渲染执行之后立刻调用一次;当组件走到当前的生命周期的时候,页面已经拥有至少一个DOM节点。
2.更新
当组件的props和state发生变化,就会触发组件的更新。
- static getDerivedStateFromProps()
- shouldComponentUpdate()
- render
- getSnapshotBeforeUpdate()
- componentDidUpdate()
在React17当中过时的生命期没有列出。
getDerivedStateFromProps
上边已经介绍过了,这个生命周期在更新组件的时候也会调用,并且在render之前。
shouldComponentUpdate
用来判断当前组件的输出是否和state、props的更改有关;默认的,state只要发生变化都会重新渲染。当props和state发生变化的时候,shouldComponentUpdate会在执行前被调用,返回值默认为true,如果是false则跳过更新(render、componentDidUpdate生命周期)。
import React from "react";
class LifeCycle extends React.Component {
constructor(props) {
super(props);
this.state = {name: "12345"};
}
render() {
console.log("render")
return <h1>{this.state.name}</h1>
}
shouldComponentUpdate(nextProps, nextState, nextContext) {
console.log(nextProps, nextState, nextContext);
return true;
}
componentDidMount(){
console.log("componentDidMount");
this.time=setInterval(()=>{
this.setState((state)=>({
name:state.name+"6",
}))
},1000)
}
componentDidUpdate(prevProps, prevState, snapshot) {
console.log("componentDidUpdate")
}
}
export default LifeCycle;
执行的结果:
生命周期中的return改成false:
getSnapshotBeforeUpdate
getSnapshotBeforeUpdate在最近一次渲染输出(提交到 DOM 节点)之前调用。它使得组件能在发生更改之前从 DOM 中捕获一些信息(例如,滚动位置)。此生命周期方法的任何返回值将作为第三个参数传递给 componentDidMount。
import React from "react";
class LifeCycle extends React.Component {
constructor(props) {
super(props);
this.state = {name: "12345"};
}
render() {
console.log("render")
return <h1>{this.state.name}</h1>
}
shouldComponentUpdate(nextProps, nextState, nextContext) {
console.log(nextProps, nextState, nextContext);
return true;
}
componentDidMount(){
console.log("componentDidMount");
this.time=setInterval(()=>{
this.setState((state)=>({
name:state.name+"6",
}))
},1000)
}
getSnapshotBeforeUpdate(){
return "789"
}
componentDidUpdate(prevProps, prevState, snapshot) {
console.log(snapshot)
}
}
export default LifeCycle;
componentDidUpdate
componentDidUpdate会在组件更新之后被立即调用,首次渲染不会执行这个方法。
在这个生命周期中也可以使用setState,但是必须使用条件语句加以限制,否则就会执行渲染-更新-渲染-更新最终导致死循环。
import React from "react";
class LifeCycle extends React.Component {
constructor(props) {
super(props);
this.state = {name: "12345"};
}
render() {
console.log("render")
return <h1>{this.state.name}</h1>
}
componentDidMount() {
console.log("componentDidMount");
this.time = setInterval(() => {
this.setState((state) => ({
name: state.name + "6",
}))
}, 1000)
}
componentDidUpdate(prevProps, prevState, snapshot) {
console.log(prevProps, prevState)
clearInterval(this.time);
this.setState((state) => ({
name: state.name + "7",
}))
}
}
export default LifeCycle;
3.卸载
- componentWillUnmount
componentWillUnmount会在组件销毁或者卸载之前调用,在此方法会执行一些必要的操作,比如如果没有使用clearInterval,这个方法就会清楚它。
这个方法中不应该调用setState,就算使用了也不会渲染。