React 组件生命周期
分三个阶段来看React
组件的生命周期
挂载阶段
当组件初次挂载,会有以下几个动作
- 执行
constructor
构造函数,如果组件内部没有使用到state
或者不需要对事件处理函数绑定this
,则这个构造函数可以不写 - 执行
static getDerivedStateFromProps
,这个方法接收两个参数,nextprops
和nextState
,可以获取到最新的属性和状态,在挂载阶段这两个值都是初始绑定的值,该方法有个返回值,它可以返回一个对象来更新state
,如果返回null
,则不对state
进行修改,否则会修改state
(浅合并) - 执行
render
,更新属性和状态 - 渲染组件,更新
DOM
- 执行
componentDidMount
,组件已经挂在,通常在这个方法里做数据请求操作,或者订阅事件等
- 执行
更新阶段
当组件的
props
或者state
有更新的时候,就会触发组件的更新- 执行
static getDerivedStateFromProps
,和挂载阶段一样。 - 执行
shouldComponentUpdate
,同样这个方法接收两个参数,nextprops
和nextState
,可以获取到最新的属性和状态,有一个返回值为true
或者false
,如果为false
,组件将不进行更新,后面的几个个动作都不会执行,这个函数通常用作性能优化。 - 执行
render
,更新属性和状态 - 执行
getSnapshotBeforeUpdate
,这个方法在最近一次渲染输出(提交到DOM
节点)之前调用,此生命周期方法的任何返回值将作为参数传递给componentDidUpdate
作为第三个参数(如果不返回值,componentDidUpdate
第三个参数将会接收到undefined,开发工具里面此时会报错,但不影响代码运行)。需要特别注意这个方法的入参,由于属性和状态已经更改了,因此这个方法的接收两个入参prevProps
和prevState
,分别是修改前的props
和state
。 - 渲染组件,更新
DOM
- 执行
componentDidUpdate
,这个方法在更新完成后调用,接收两个入参prevProps
和prevState
,也分别是修改前的props
和state
。如果getSnapshotBeforeUpdate
方法有返回值,将作为第三个参数传入给componentDidUpdate
。
我们可以总结出,可以以
rener
函数分界,render
函数执行之前,属性和状态还没有发生变更, 在它之前的两个方法getDerivedStateFromProps
和shouldComponentUpdate
的参数获取的是将要发生变更的属性和方法,而在render
函数执行之后,属性和状态已经变更了,在它之后的两个方法getSnapshotBeforeUpdate
和componentDidUpdate
的参数获取的是修改之前的属性和方法。这样的好处是我们可以在这个数据更改前后做一些自定义的操作,比如在
shouldComponentUpdate
方法中对当前状态和修改的状态做深度比较,完全相等才不去更新组件,否则更新。又比如在componentDidUpdate
中,可以对比修改前的状态和修改后的状态,例如this.props.userID !== prevProps.userID
,如果两者不相等,就去调用数据更新接口,可以在componentDidUpdate
中直接调用setState
更新组件,但请注意它必须被包裹在一个条件语句里,例如上面这种,否则会导致死循环。- 执行
卸载阶段
- 执行
componentWillUnmount
,会在组件卸载及销毁之前直接调用。在此方法中执行必要的清理操作,例如,清除定时器,取消网络请求或清除在componentDidMount
中创建的订阅等。componentWillUnmount
中不应调用setState
,因为该组件将永远不会重新渲染。组件实例卸载后,将永远不会再挂载它。
- 执行
父子组件生命周期执行顺序
通过以下代码来进行观察
import React from 'react'
class LifeCycleChild extends React.Component {
constructor(props) {
super(props)
this.state = {}
console.log('child constructor');
}
static getDerivedStateFromProps (nextProps, nextState) {
console.log('child getDerivedStateFromProps');
return null
}
componentDidMount () {
console.log('child componentDidMount');
}
shouldComponentUpdate (nextProps, nextState) {
console.log('child shouldComponentUpdate');
return true
}
getSnapshotBeforeUpdate (prevProps, prevState) {
console.log('child getSnapshotBeforeUpdate');
}
componentDidUpdate (prevProps, prevState, snapshot) {
console.log('child componentDidUpdate');
}
componentWillUnmount() {
console.log('child componentWillUnmount')
}
render () {
console.log('child render');
return (
<div>
<p>{this.props.text}</p>
</div>
)
}
}
class LifeCycleFather extends React.Component {
constructor(props) {
super(props)
this.state = {
text: 'hello'
}
console.log('father constructor')
}
componentDidMount () {
console.log('father componentDidMount');
}
static getDerivedStateFromProps () {
console.log('father getDerivedStateFromProps');
return null
}
shouldComponentUpdate () {
console.log('father shouldComponentUpdate');
return true
}
getSnapshotBeforeUpdate () {
console.log('father getSnapshotBeforeUpdate');
return 'father'
}
componentDidUpdate () {
console.log('father componentDidUpdate');
}
componentWillUnmount() {
console.log('father componentWillUnmount')
}
render () {
console.log('father render');
return <>
<p>father</p>
<button onClick={() => this.setState({text: 'new text'})}>修改text</button>
<LifeCycleChild text={this.state.text} />
</>
}
}
class WrappedComp extends React.Component {
constructor(props){
super(props)
this.state = {
isShow: true
}
}
render() {
return <>
<button onClick={()=>{this.setState({isShow: !this.state.isShow})}}>卸载组件</button>
{ this.state.isShow ? <LifeCycleFather /> : null }
</>
}
}
export default WrappedComp
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
挂载阶段
father constructor father getDerivedStateFromProps father render child constructor child getDerivedStateFromProps child render child componentDidMount father componentDidMount
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
更新阶段
father getDerivedStateFromProps father shouldComponentUpdate father render child getDerivedStateFromProps child shouldComponentUpdate child render child getSnapshotBeforeUpdate father getSnapshotBeforeUpdate child componentDidUpdate father componentDidUpdate
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
卸载阶段
father componentWillUnmount child componentWillUnmount
- 1
- 2
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 289211569@qq.com
未找到相关的 Issues 进行评论
请联系 @daryl-lau 初始化创建