React生命周期详谈
KongHou

🌿 React 生命周期详解:从创建到销毁的完整旅程

在使用 React 构建组件化应用的过程中,我们经常会听到一个重要的概念——生命周期(Lifecycle)
生命周期是指一个组件从创建(Mounting)更新(Updating)卸载(Unmounting)的整个过程。

React 在不同阶段提供了一系列 生命周期方法(Lifecycle Methods),让我们有机会在合适的时机执行副作用操作,比如发起网络请求、操作 DOM、保存状态等。


🧩 一、React 生命周期总览

React 组件的生命周期可以分为三个阶段:

阶段 说明
挂载(Mounting) 组件被创建并插入到 DOM 中
更新(Updating) 当组件的 state 或 props 发生变化时重新渲染
卸载(Unmounting) 组件从 DOM 中被移除

对于类组件(Class Component)和函数组件(Function Component,Hooks),它们的生命周期表现有所不同。


🧱 二、类组件生命周期详解

React 16 之后,类组件的生命周期主要包括以下几个方法:

1. 挂载阶段

方法 调用时机 用途
constructor() 组件被创建时调用 初始化 state、绑定方法
static getDerivedStateFromProps() render() 前调用 根据 props 更新 state
render() 渲染 UI 返回要显示的 JSX
componentDidMount() 组件挂载后调用 执行副作用(如请求数据、操作 DOM)
  • constructor(props)

    构造函数,在组件创建时调用,用于初始化状态和绑定事件处理函数。
    在构造函数中调用  super(props)  来调用父类的构造函数,并将 props 传递给父类。
    初始化组件的状态可以通过  this.state = { }  实现。

  • static getDerivedStateFromProps(props, state)

    当组件接收到新的 props 时调用,在渲染之前执行。
    用于根据新的 props 计算并更新组件的状态。
    应返回一个对象来更新状态,或者返回 null 来表示不需要更新状态。

  • render()

    必需的生命周期方法,用于渲染组件的 UI。
    应返回一个 React 元素,描述组件的输出。
    不应该在这个方法中修改组件的状态或执行副作用操作。

  • componentDidMount()

    在组件的初始渲染之后立即被调用的
    通常在这个方法中执行一些初始化操作(比如发起网络请求、订阅事件、获取初始数据)
    这个方法只会在组件的生命周期中被调用一次,因此适合进行一次性的初始化工作

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Example extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
console.log('constructor');
}

componentDidMount() {
console.log('componentDidMount');
document.title = `Count: ${this.state.count}`;
}

render() {
console.log('render');
return <h1>{this.state.count}</h1>;
}
}

📌 执行顺序:
constructor → render → componentDidMount


2. 更新阶段

当组件的 props 或 state 发生变化 时,组件会重新渲染。主要生命周期方法如下:

方法 调用时机 用途
static getDerivedStateFromProps() 每次渲染前调用 根据 props 更新 state
shouldComponentUpdate() 决定是否重新渲染 性能优化
render() 重新渲染组件 更新 UI
getSnapshotBeforeUpdate() 更新前获取 DOM 状态 如滚动位置等
componentDidUpdate() 更新完成后调用 发起请求、操作更新后的 DOM
  • shouldComponentUpdate(nextProps, nextState)

    在组件接收到新的 props 或者 state 时被调用,在渲染之前执行。
    可以根据新的 props 或者 state 决定是否需要重新渲染组件。
    默认返回 true,表示组件将会重新渲染,可以通过返回 false 来阻止重新渲染,以提升性能。

  • render()

    必需的生命周期方法,用于渲染组件的 UI。
    应返回一个 React 元素,描述组件的输出。
    不应该在这个方法中修改组件的状态或执行副作用操作。

  • getSnapshotBeforeUpdate(prevProps, prevState)

    在最新的渲染输出被提交到 DOM 之前调用。
    用于获取更新前的 DOM 快照或执行一些 DOM 操作。
    返回的值将作为  componentDidUpdate  方法的第三个参数传递。

  • componentDidUpdate(prevProps, prevState, snapshot)

    在组件更新完成后立即调用。
    通常用于执行一些副作用操作,比如更新后的 DOM 操作、发送网络请求等。
    可以访问到更新之前的 props、state,以及通过  getSnapshotBeforeUpdate  返回的值。

示例:

1
2
3
4
5
componentDidUpdate(prevProps, prevState) {
if (prevState.count !== this.state.count) {
console.log('count 改变了');
}
}

📌 执行顺序:
getDerivedStateFromProps → shouldComponentUpdate → render → getSnapshotBeforeUpdate → componentDidUpdate


3. 卸载阶段

方法 调用时机 用途
componentWillUnmount() 组件即将卸载时调用 清除定时器、取消订阅、释放资源等
  • componentWillUnmount()

    在组件即将被销毁并从 DOM 中移除之前调用。
    用于执行一些清理工作,比如取消订阅、清除定时器等。
    在这个方法中不能调用 setState,因为组件即将被销毁。

示例:

1
2
3
4
componentWillUnmount() {
clearInterval(this.timer);
console.log('组件被卸载');
}

⚛️ 三、函数组件的生命周期(Hooks)

函数组件没有传统的生命周期方法,而是通过 React Hooks(如 useEffect)实现相同的效果。

1. 模拟挂载和卸载

1
2
3
4
5
6
7
8
9
10
import { useEffect } from 'react';

function Example() {
useEffect(() => {
console.log('组件挂载');
return () => {
console.log('组件卸载');
};
}, []);
}

📌 useEffect 第二个参数为 [] 时,等价于:

  • componentDidMount
  • componentWillUnmount

2. 模拟更新

1
2
3
useEffect(() => {
console.log('count 更新了');
}, [count]);

📌 当依赖项 count 改变时触发,等价于:

  • componentDidUpdate

3. 多个 useEffect 拆分逻辑

在函数组件中,我们可以声明多个 useEffect 来分别管理不同的副作用逻辑:

1
2
3
4
5
6
7
8
9
useEffect(() => {
console.log('监听窗口大小变化');
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);

useEffect(() => {
document.title = `Count: ${count}`;
}, [count]);

🧠 四、生命周期与 Fiber 架构的关系

React 16 引入了 Fiber 架构,它让生命周期的执行变得更“可中断”、“可恢复”。
这意味着:

  • 某些生命周期方法(如 componentWillMountcomponentWillUpdate)可能在异步渲染中被多次调用;
  • 因此它们被标记为 不安全生命周期(Unsafe Lifecycle)

推荐使用以下“安全生命周期”:

  • componentDidMount
  • componentDidUpdate
  • componentWillUnmount
  • getDerivedStateFromProps
  • getSnapshotBeforeUpdate

🧩 五、生命周期对比图

以下是常见生命周期的执行顺序(简化版):

1
2
3
4
5
6
7
8
挂载阶段:
constructor → getDerivedStateFromProps → render → componentDidMount

更新阶段:
getDerivedStateFromProps → shouldComponentUpdate → render → getSnapshotBeforeUpdate → componentDidUpdate

卸载阶段:
componentWillUnmount

🔍 六、总结对比表

功能 类组件 函数组件
挂载 componentDidMount() useEffect(() => {...}, [])
更新 componentDidUpdate() useEffect(() => {...}, [dep])
卸载 componentWillUnmount() useEffect(() => return {...}, [])
性能优化 shouldComponentUpdate() React.memo()

💬 七、结语

理解生命周期,是深入掌握 React 的关键。
在类组件中,我们通过生命周期方法控制组件行为;
而在函数组件中,我们用 useEffectuseMemouseLayoutEffect 等 Hooks 来优雅地管理副作用。

掌握生命周期,你就能更好地:

  • 控制组件的行为;
  • 避免不必要的渲染;
  • 编写更高效、更易维护的代码。
Powered by Hexo & Theme Keep
Total words 23.5k