React 组件生命周期

  1. React 组件生命周期
  2. 父子组件生命周期执行顺序

React 组件生命周期

分三个阶段来看React组件的生命周期

  • 挂载阶段

    当组件初次挂载,会有以下几个动作

    1. 执行constructor构造函数,如果组件内部没有使用到state或者不需要对事件处理函数绑定this,则这个构造函数可以不写
    2. 执行 static getDerivedStateFromProps,这个方法接收两个参数,nextpropsnextState,可以获取到最新的属性和状态,在挂载阶段这两个值都是初始绑定的值,该方法有个返回值,它可以返回一个对象来更新 state,如果返回 null,则不对state进行修改,否则会修改state(浅合并)
    3. 执行render,更新属性和状态
    4. 渲染组件,更新DOM
    5. 执行componentDidMount,组件已经挂在,通常在这个方法里做数据请求操作,或者订阅事件等
  • 更新阶段

    当组件的props或者state有更新的时候,就会触发组件的更新

    1. 执行 static getDerivedStateFromProps,和挂载阶段一样。
    2. 执行shouldComponentUpdate,同样这个方法接收两个参数,nextpropsnextState,可以获取到最新的属性和状态,有一个返回值为true或者false,如果为false,组件将不进行更新,后面的几个个动作都不会执行,这个函数通常用作性能优化。
    3. 执行render,更新属性和状态
    4. 执行getSnapshotBeforeUpdate,这个方法在最近一次渲染输出(提交到 DOM 节点)之前调用,此生命周期方法的任何返回值将作为参数传递给componentDidUpdate作为第三个参数(如果不返回值,componentDidUpdate第三个参数将会接收到undefined,开发工具里面此时会报错,但不影响代码运行)。需要特别注意这个方法的入参,由于属性和状态已经更改了,因此这个方法的接收两个入参prevPropsprevState,分别是修改前的propsstate
    5. 渲染组件,更新DOM
    6. 执行componentDidUpdate,这个方法在更新完成后调用,接收两个入参prevPropsprevState,也分别是修改前的propsstate。如果getSnapshotBeforeUpdate方法有返回值,将作为第三个参数传入给componentDidUpdate

    我们可以总结出,可以以rener函数分界,render函数执行之前,属性和状态还没有发生变更, 在它之前的两个方法getDerivedStateFromPropsshouldComponentUpdate的参数获取的是将要发生变更的属性和方法,而在render函数执行之后,属性和状态已经变更了,在它之后的两个方法getSnapshotBeforeUpdatecomponentDidUpdate的参数获取的是修改之前的属性和方法。

    这样的好处是我们可以在这个数据更改前后做一些自定义的操作,比如在shouldComponentUpdate方法中对当前状态和修改的状态做深度比较,完全相等才不去更新组件,否则更新。又比如在componentDidUpdate中,可以对比修改前的状态和修改后的状态,例如this.props.userID !== prevProps.userID,如果两者不相等,就去调用数据更新接口,可以在componentDidUpdate中直接调用setState更新组件,但请注意它必须被包裹在一个条件语句里,例如上面这种,否则会导致死循环。

  • 卸载阶段

    1. 执行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
javascriptCopy
  • 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
    
    Copy
    • 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
    
    Copy
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
  • 卸载阶段

    father componentWillUnmount
    child componentWillUnmount
    
    Copy
    • 1
    • 2

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 289211569@qq.com

未找到相关的 Issues 进行评论

请联系 @daryl-lau 初始化创建