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
挂载阶段
father constructor father getDerivedStateFromProps father render child constructor child getDerivedStateFromProps child render child componentDidMount father componentDidMount
更新阶段
father getDerivedStateFromProps father shouldComponentUpdate father render child getDerivedStateFromProps child shouldComponentUpdate child render child getSnapshotBeforeUpdate father getSnapshotBeforeUpdate child componentDidUpdate father componentDidUpdate
卸载阶段
father componentWillUnmount child componentWillUnmount
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 289211569@qq.com