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
  • 挂载阶段

    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