React系列--生命周期

155 阅读3分钟

首先让我们使用 Vite 来创建一个新的 React 项目。

npm init vite@latest

React 版本:18.0.0

image.png

按照提示的命令把项目跑起来。

React 生命周期钩子

根据官网的顺序我们开始在不同的生命周期里写一些 log

挂载 Mounting

image.png

当组件实例被创建并插入 DOM 中时,其生命周期调用顺序如下:

constructor() -> static getDerivedStateFromProps() -> render() -> componentDidMount()

  1. 首先是 constructor() 。

我们新建一个 Count.jsx 组件, 并修改 App.jsx ,将 Count 组件引入。

// Count.jsx
import React, { Component } from 'react'

export default class Count extends Component {
  constructor(props) {
    // 必须先调用 super
    super(props)
    console.log('constructor')
  }
  render() {
    return (
      <div>Count</div>
    )
  }
}

// App.jsx
import Count from './Count'

function App() {
  return (
    <Count />
  )
}

export default App

此时意外地发现, 'constructor' 被打印了两次。

image.png

经过搜索后知道原来是因为严格模式,这里先不做赘述,直接把严格模式去掉就正常了。

我们关注生命周期。

import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'

ReactDOM.createRoot(document.getElementById('root')).render(
  // 删除这里的严格模式
  <React.StrictMode>
    <App />
  </React.StrictMode>
)

  1. 然后是 static getDerivedStateFromProps()
import React, { Component } from 'react'

export default class Count extends Component {
  constructor(props) {
    // 必须先调用 super
    super(props)
    console.log('constructor')
  }
  static getDerivedStateFromProps(props, state) {
    console.log('getDerivedStateFromProps')
  }
  render() {
    return (
      <div>Count</div>
    )
  }
}

直接写发现会报两个错误:

image.png

大意是必须在 constructor 中初始化 state ,另外就是此生命周期必须返回 state 对象或者 null。

行吧,那就加两行代码。

import React, { Component } from 'react'

export default class Count extends Component {
  constructor(props) {
    // 必须先调用 super
    super(props)
    console.log('constructor')
    this.state = {}
  }
  static getDerivedStateFromProps(props, state) {
    console.log('getDerivedStateFromProps')
    // 必须返回 state 对象或者 null
    return state
  }
  render() {
    return (
      <div>Count</div>
    )
  }
}
  1. 接下来是 render()

这倒是没什么意外,直接在 render()里打印 'render'

  1. componentDidMount()

这也没什么意外,直接在 componentDidMount()里打印 'componentDidMount'

通常在这里发起网络请求获取数据。

更新 Updating

image.png

当组件的 props 或 state 发生变化时会触发更新。

我们先来改写一下 Count.jsx 以做一个更新组件状态的功能,页面展示一个数值,然后来一个按钮,点击按钮数值自动加 1,代码如下:

import React, { Component } from 'react'

export default class Count extends Component {
  constructor(props) {
    // 必须先调用 super
    super(props)
    console.log('constructor')
    this.state = {
      count: 0
    }
  }
  static getDerivedStateFromProps(props, state) {
    console.log('getDerivedStateFromProps')
    // 必须返回 state 对象或者 null
    return state
  }
  clickHandler = () => {
    this.setState({
      count: this.state.count + 1
    })
  }
  render() {
    console.log('render')
    return (
      <div>
        <h1>Count 组件</h1>
        <p>数值:{ this.state.count }</p>
        <button onClick={ this.clickHandler }>点击递增</button>
      </div>
    )
  }
  componentDidMount() {
    console.log('componentDidMount')
  }
}

组件更新时生命周期的调用顺序如下:

  1. static getDerivedStateFromProps()
  2. shouldComponentUpdate()
shouldComponentUpdate(nextProps, nextState) {
  console.log('shouldComponentUpdate')
  // 必须返回布尔值,默认为true
  return true
}

如果 shouldComponentUpdate() 返回 false,则不会调用 render()。

  1. render()
  2. getSnapshotBeforeUpdate()
getSnapshotBeforeUpdate(prevProps, prevState) {
  console.log('getSnapshotBeforeUpdate')
  // 必须有返回值,默认写null
  return null
}
  1. componentDidUpdate()
componentDidUpdate(prevProps, prevState, snapshot) {
  console.log('componentDidUpdate')
}

首次渲染不会执行此方法。

卸载 Unmounting

image.png

当组件从 DOM 中移除时会调用如下方法:

  1. componentWillUnmount()

会在组件卸载及销毁之前直接调用。在此方法中执行必要的清理操作,例如,清除 timer,取消网络请求或清除在 componentDidMount() 中创建的订阅等。

错误处理 Error Handling

image.png

当渲染过程,生命周期,或子组件的构造函数中抛出错误时,会调用如下方法:

  1. static getDerivedStateFromError()
  2. componentDidCatch()

注意点:

两者都是在后代组件抛出错误后才会被调用。

源码地址

github.com/ximuli/reac…

参考链接

两个 React 官网的链接

  1. React.Component – React (reactjs.org)
  2. React lifecycle methods diagram (wojtekmaj.pl)