React组件生命周期详解

28 阅读4分钟

1.概述

意义:组件的生命周期有助于理解组件的运行方式,完成更复杂的组件功能、分析组件错误原因等

组件的生命周期: 组件从被创建到挂载到页面中运行,再到组件不在时卸载的过程,生命周期的每个阶段总是伴随着一些方法调用,这些方法就是生命周期的钩子函数

构造函数的作用:为开发人员在不同阶段操作组件提供了实际

请添加图片描述

2.生命周期阶段

2.1创建时(挂载阶段)

2.1.1 原理

  • 执行时机:组件创建时(页面加载时)
  • 执行顺序 请添加图片描述请添加图片描述

2.1.2 效果

在这里插入图片描述

2.1.3 代码

//创建时  1、constructor,2、render,3、componentDidMount
// 组件的生命周期
class App extends React.Component{

  constructor(props) {
    super(props)
    console.warn('生命周期钩子函数: constructor')
  }

  componentDidMount(){
    const title = document.getElementById('title')
    console.log(title);
    console.warn('生命周期钩子函数: componentDidMount')
  }

  render(){
    console.warn('生命周期钩子函数: render')
    return(
      <div>
        <h1 id='title'>统计豆豆被打的次数</h1>
        <button id='btn'>打豆豆</button>
      </div>
    )
  }
}

const container = createRoot(document.getElementById('root'))
container.render(<App />)

2.2 更新时

2.2.1 原理

执行时机:setState()、 forceUpdate()、 组件接收到新的props

说明:以上三者任意一种变化,组件就会重新渲染

执行顺序 请添加图片描述 请添加图片描述

2.2.2 效果

在这里插入图片描述

2.2.3 代码

//更新时1.setState,2.forceUpdate(),3.组件接收到新的props
class App extends React.Component{

  constructor(props) {
    super(props)
    this.state = {
      count:0
    }
  }

  handleClick = () => {
    this.setState({
      count:this.state.count + 1
    })
    //强制更新
    this.forceUpdate()
  }
  
  render(){
    return(
      <div>
        <Counter count={this.state.count}/>
        <button onClick={this.handleClick}>打豆豆</button>
      </div>
    )
  }
}

class Counter extends React.Component{
  render(){
    console.warn('子组件生命周期钩子函数: render')
    return  <h1 id='title'>统计豆豆被打的次数:{this.props.count}</h1>
  }

  //如果要调用 setState() 更新状态,必须要放在一个if条件中
  componentDidUpdate(prevProps){
    console.warn('生命周期钩子函数: componentDidUpdate');
    if (prevProps.count != this.props.count) {
      this.setState({})
    }
    console.log('上一次的props:',prevProps.count);
    //获取DOM
    const title = document.getElementById('title')
    console.log(title.innerHTML);
  }
}

const container = createRoot(document.getElementById('root'))
container.render(<App />)

2.3 卸载时

2.3.1 原理

执行时机:组件从页面中消失

作用:用来做清理操作请添加图片描述

2.3.2 效果

在这里插入图片描述

2.3.3 代码

class App extends React.Component{

  constructor(props) {
    super(props)
    this.state = {
      count:0
    }
  }

  handleClick = () => {
    this.setState({
      count:this.state.count + 1
    })
    //强制更新
    this.forceUpdate()
  }
  
  render(){
    return(
      <div>
        {
          this.state.count > 3
          ? <h1>Game Over</h1>
          : <Counter count={this.state.count} handleClick={this.handleClick}/>
        }
        <button onClick={this.handleClick}>打豆豆</button>
      </div>
    )
  }
}

class Counter extends React.Component{
  componentDidMount(){
    //开启定时器
    this.timeId = setInterval(()=>{
      this.props.handleClick()
      console.log('自动打豆豆');
    },500)
  }
  render(){
    console.warn('子组件生命周期钩子函数: render')
    return  <h1 id='title'>统计豆豆被打的次数:{this.props.count}</h1>
  }

  componentWillUnmount(){
    //清理定时器
    clearInterval(this.timeId)
    console.warn('生命周期钩子函数:componentWillUnmount');
  }

  //如果要调用 setState() 更新状态,必须要放在一个if条件中
  componentDidUpdate(prevProps){
    console.warn('生命周期钩子函数: componentDidUpdate');
    if (prevProps.count != this.props.count) {
      this.setState({})
    }
    console.log('上一次的props:',prevProps.count);
    //获取DOM
    const title = document.getElementById('title')
    console.log(title.innerHTML);
  }
}

const container = createRoot(document.getElementById('root'))
container.render(<App />)

2.4 不常用的钩子函数

2.4.1 getDerivedStateFromProps()

  • getDerivedStateFromProps 会在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用。它应返回一个对象来更新 state,如果返回 null 则不更新任何内容
  • 不管原因是什么,都会在每次渲染前触发此方法

2.4.2 shouldComponentUpdate()

  • 根据 shouldComponentUpdate() 的返回值,判断 React 组件的输出是否受当前 state 或 props 更改的影响。默认行为是 state 每次发生变化组件都会重新渲染
  • 当 props 或 state 发生变化时,shouldComponentUpdate() 会在渲染执行之前被调用。返回值默认为 true

2.4.2 getSnapshotBeforeUpdate()

  • getSnapshotBeforeUpdate() 在最近一次渲染输出(提交到 DOM 节点)之前调用。它使得组件能在发生更改之前从 DOM 中捕获一些信息(例如,滚动位置)。此生命周期的任何返回值将作为参数传递给 componentDidUpdate()
  • 此用法并不常见,但它可能出现在 UI 处理中,如需要以特殊方式处理滚动位置的聊天线程等

3.完整源码

import React from 'react';
import {createRoot} from 'react-dom/client'

//创建时  1、constructor,2、render,3、componentDidMount
// 组件的生命周期
// class App extends React.Component{

//   constructor(props) {
//     super(props)
//     console.warn('生命周期钩子函数: constructor')
//   }

//   componentDidMount(){
//     const title = document.getElementById('title')
//     console.log(title);
//     console.warn('生命周期钩子函数: componentDidMount')
//   }

//   render(){
//     console.warn('生命周期钩子函数: render')
//     return(
//       <div>
//         <h1 id='title'>统计豆豆被打的次数</h1>
//         <button id='btn'>打豆豆</button>
//       </div>
//     )
//   }
// }

//更新时1.setState,2.forceUpdate(),3.组件接收到新的props
// class App extends React.Component{

//   constructor(props) {
//     super(props)
//     this.state = {
//       count:0
//     }
//   }

//   handleClick = () => {
//     this.setState({
//       count:this.state.count + 1
//     })
//     //强制更新
//     this.forceUpdate()
//   }
  
//   render(){
//     return(
//       <div>
//         <Counter count={this.state.count}/>
//         <button onClick={this.handleClick}>打豆豆</button>
//       </div>
//     )
//   }
// }

// class Counter extends React.Component{
//   render(){
//     console.warn('子组件生命周期钩子函数: render')
//     return  <h1 id='title'>统计豆豆被打的次数:{this.props.count}</h1>
//   }

//   //如果要调用 setState() 更新状态,必须要放在一个if条件中
//   componentDidUpdate(prevProps){
//     console.warn('生命周期钩子函数: componentDidUpdate');
//     if (prevProps.count != this.props.count) {
//       this.setState({})
//     }
//     console.log('上一次的props:',prevProps.count);
//     //获取DOM
//     const title = document.getElementById('title')
//     console.log(title.innerHTML);
//   }
// }

class App extends React.Component{

  constructor(props) {
    super(props)
    this.state = {
      count:0
    }
  }

  handleClick = () => {
    this.setState({
      count:this.state.count + 1
    })
    //强制更新
    this.forceUpdate()
  }
  
  render(){
    return(
      <div>
        {
          this.state.count > 3
          ? <h1>Game Over</h1>
          : <Counter count={this.state.count} handleClick={this.handleClick}/>
        }
        <button onClick={this.handleClick}>打豆豆</button>
      </div>
    )
  }
}

class Counter extends React.Component{
  componentDidMount(){
    //开启定时器
    this.timeId = setInterval(()=>{
      this.props.handleClick()
      console.log('自动打豆豆');
    },500)
  }
  render(){
    console.warn('子组件生命周期钩子函数: render')
    return  <h1 id='title'>统计豆豆被打的次数:{this.props.count}</h1>
  }

  componentWillUnmount(){
    //清理定时器
    clearInterval(this.timeId)
    console.warn('生命周期钩子函数:componentWillUnmount');
  }

  //如果要调用 setState() 更新状态,必须要放在一个if条件中
  componentDidUpdate(prevProps){
    console.warn('生命周期钩子函数: componentDidUpdate');
    if (prevProps.count != this.props.count) {
      this.setState({})
    }
    console.log('上一次的props:',prevProps.count);
    //获取DOM
    const title = document.getElementById('title')
    console.log(title.innerHTML);
  }
}
const container = createRoot(document.getElementById('root'))
container.render(<App />)