生命周期函数指在某一时刻组件会自动调用并执行的函数。React每个类组件都包含生命周期方法
,我们可以重写这些方法,以便于在运行过程中特定的阶段执行这些方法。例如:
我们希望在第一次将其呈现到DOM时设置一个计时器Clock
。这在React中称为“安装”。
我们也想在删除由产生的DOM时清除该计时器Clock
。这在React中称为“卸载”。
参考:生命周期
完整的生命周期图
-
常用简单周期函数
-
constructor:构造函数,一般在这里做初始化操作
-
render:渲染周期函数,在这里做用户界面的渲染,必须要有该周期函数
-
componentDidMount:组件挂载完毕周期,该周期一般用于做网络请求
-
getSnapshotBeforeUpdate:在更新前获取快照(更新前的一个备份)周期函数,一般在这里获取更新之前的一些信息的,例如获取组件在更新之前的高度、宽度等。该周期函数不能单独使用,一定要配合componentDidUpdate一起使用,否则报错。该周期函数需要有返回值,返回我们需要在更新前获取的数据
-
componentDidUpdate:组件更新完毕的周期函数,在组件渲染完毕后触发,该周期可能触发多次
-
componentWillUnmount:组件解除挂载之前触发,一般在该周期中做组件的销毁善后处理(副作用代码的清理,例如:定时器、事件监听等,专门做卸磨杀驴)
-
案例:
父组件与子组件的(常见)生命周期先后顺序
父组件
/**
* 生命周期
*/
import React, { Component } from 'react'
import Child from './components/Child';
export default class App extends Component {
state ={
show: false,
num:100
}
constructor(){
super()
console.log('1.构造函数触发');
}
render() {
console.log('2.页面渲染');
return (
<div>
<button onClick={() => this.setState({num:this.state.num+1})}>{this.state.num}</button>
{/** 类似于 vue中的v-if */}
{this.state.show ? <Child></Child> : null }
<button onClick={() => this.setState({show:!this.state.show})}>{this.state.show? '隐藏' : '不隐藏'}</button>
</div>
)
}
componentDidMount(){
// 操作DOM节点 发送请求 执行副作用
console.log('3.组件挂载完毕');
}
componentDidUpdate(){
// 更新后操作DOM
console.log('4.组件更新完毕');
}
componentWillUnmount() {
// 资源回收操作 清除副作用 取消请求 清空定时器
console.log('5.组件卸载');
}
}
子组件
import React, { Component } from 'react'
export default class Child extends Component {
constructor(){
super()
console.log('1.子组件构造函数触发');
}
render() {
console.log('2.子组件页面渲染');
return (
<div>
子组件
</div>
)
}
componentDidMount(){
console.log('3.子组件挂载完毕');
}
componentDidUpdate(){
console.log('4.子组件更新完毕');
}
componentWillUnmount() {
console.log('5.子组件卸载');
}
}
效果
getDerivedStateFromProps:(应该写在子组件中)
-
相对复杂的生命周期函数
-
注意点:
-
必须需要写在子组件中
-
必须要有state
-
该周期函数必须返回state对象或者null(如果返回null则表示不更新state,如果返回对象则表示以对象的数据更新state)
-
-
作用:
-
能够实现props里的数据可读可写
-
数据可以实现集中管理
-
-
案例:
父组件:
/**
* 不常用生命周期
*/
import React, { Component } from 'react'
import Child from './components/Child';
export default class App extends Component {
state ={
num:100
}
render() {
console.log('2.页面渲染');
return (
<div>
<Child msg="父传子"></Child>
<button onClick={() => this.setState({num:this.state.num+1})}>{this.state.num}</button>
</div>
)
}
}
子组件:
import React, { Component } from "react";
export default class Child extends Component {
// 使props 和 state 进行关联
state = {}
// 将组件的外部传递的 props 映射到组件内部状态的state
static getDerivedStateFromProps(props, state) {
console.log(props)
console.log(state)
// 必须具有返回值 返回的内容必须是对象结构 返回给state
return props
}
render() {
// eslint-disable-next-line react/no-direct-mutation-state
this.state = this.props
console.log(this.state);
return <div>子组件2</div>;
}
}
shouldComponentUpdate:
-
作用:用于决定非首次渲染后的渲染是否执行(意义:优化组件性能,减少不必要的re-render)
-
注意点:
-
该函数返回bool值,true继续render,false表示停止render
-
虽然这个函数用于做性能优化,但是其过于复杂,因此一般不用。那怎么进行性能优化?(替代方案:纯净组件PureComponent,可以使用纯净组件来替代现有的Component)如下图:
-
但是纯净组件也存在问题,其不能解决深拷贝引发的问题
-
案例:
import React, { Component } from 'react'
export default class App extends Component {
state ={
num :100
}
// 参数为更新后的props 和 state
// 该周期函数必须具有返回值 true 渲染 false 不渲染
// 该生命周期控制页面是否渲染 控制渲染时机
shouldComponentUpdate(nextProps, nextState){
console.log(nextProps);
console.log(nextState); //更新后的值
if(nextState.num%2 === 0){
return true
}else {
return false
}
}
render() {
return (
<div>
<button onClick={() => this.setState({num: this.state.num + 1 })}>{this.state.num}</button>
</div>
)
}
}
案例2:
import React, {PureComponent } from 'react'
export default class App extends PureComponent {
state ={
num :100
}
// 参数为更新后的props 和 state
// 该周期函数必须具有返回值 true 渲染 false 不渲染
// 该生命周期控制页面是否渲染 控制渲染时机
shouldComponentUpdate(nextProps, nextState){
console.log(nextProps);
console.log(nextState); //更新后的值
if(nextState.num%2 === 0){
return true
}else {
return false
}
}
render() {
return (
<div>
<button onClick={() => this.setState({num: this.state.num + 1 })}>{this.state.num}</button>
</div>
)
}
}