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