React 的生命周期主要分为两种:类组件(Class Components) 和 函数组件(Functional Components with Hooks) 。它们实现生命周期的方式完全不同。
1. 类组件的生命周期(经典方式)
这是传统的生命周期模型,主要分为三个阶段:挂载(Mounting) 、更新(Updating) 和 卸载(Unmounting) 。

(这是一个非常经典的生命周期图,新版 React 已经废弃了一些方法)
第一阶段:挂载 (Mounting)
当组件实例被创建并插入到 DOM 中时,会按顺序调用以下方法:
-
constructor()
-
作用:组件的构造函数,第一个被执行。
-
用途:
- 初始化 state。
- 为事件处理函数绑定 this。
-
注意:这是唯一可以直接给 this.state 赋值的地方。
-
-
static getDerivedStateFromProps(props, state)
- 作用:在 render 之前调用,无论是初始挂载还是后续更新。
- 用途:让组件的 state 在 props 变化时更新。它应该返回一个对象来更新 state,或者返回 null 表示不更新。
- 注意:这是一个静态方法,无法访问 this。它很少被使用,因为通常有更简单的替代方案(如在 render 中直接使用 props,或在 componentDidUpdate 中处理)。
-
render()
- 作用:必须的方法。用于渲染 UI。
- 用途:读取 this.props 和 this.state,返回一个 React 元素(通常是 JSX)。
- 注意:render 函数应该是纯函数,意味着在不修改组件 state 的情况下,每次调用都返回相同的结果。不应在 render 中执行有副作用的操作(如 API 请求)。
-
componentDidMount()
-
作用:
在组件被挂载到 DOM **之后**立即调用。就是组件的模板(render函数里的jsx)已经从虚拟dom变成真实dom了,可以操作了。比如用queryAllselector获取了(useRef) -
用途:这是执行副作用(Side Effects)的绝佳位置。
- 发起网络请求(API calls)。
- 添加事件监听器(如 window.addEventListener)。
- 进行 DOM 操作。
-
第二阶段:更新 (Updating)
当组件的 props 或 state 发生变化时,会触发更新。组件会重新渲染,并按顺序调用以下方法:
-
static getDerivedStateFromProps(props, state)
- (同上)在每次更新前都会被调用。
-
shouldComponentUpdate(nextProps, nextState)
- 作用:在 render 之前调用,用于性能优化。
- 用途:根据 nextProps 和 nextState 判断是否需要重新渲染。默认返回 true。如果返回 false,则后续的 render()、getSnapshotBeforeUpdate() 和 componentDidUpdate() 都不会被调用。
- 注意:通常使用 React.PureComponent 或 React.memo 来自动处理这个逻辑,而不是手动编写。
-
render()
- (同上)如果 shouldComponentUpdate 返回 true,则会再次调用 render。
-
getSnapshotBeforeUpdate(prevProps, prevState)
- 作用:在 render 之后,但在 DOM 更新之前调用。
- 用途:允许你在 DOM 更新前捕获一些信息(如滚动位置)。此方法的返回值将作为第三个参数传递给 componentDidUpdate()。
- 注意:不常用,但在处理如聊天窗口滚动条等场景时很有用。
-
componentDidUpdate(prevProps, prevState, snapshot)
-
作用:在组件更新之后立即调用。
-
用途:
- 当 props 变化时,执行副作用(如根据新的 props 发起网络请求)。
- 进行 DOM 操作。
-
注意:在这里执行副作用时,务必将其包裹在条件语句中,否则可能导致无限循环。例如:if (this.props.userID !== prevProps.userID) { ... }
-
第三阶段:卸载 (Unmounting)
当组件从 DOM 中被移除时,会调用此方法:
-
componentWillUnmount()
-
作用:在组件被卸载和销毁之前调用。
-
用途:执行必要的清理操作。
- 清除定时器(clearInterval, clearTimeout)。
- 移除在 componentDidMount 中添加的事件监听器。
- 取消网络请求。
-
2. 函数组件的生命周期(现代方式 - Hooks)
在函数组件中,没有生命周期“方法”,而是通过 Hooks 来模拟生命周期的各个阶段。这种方式更灵活、代码更简洁。
核心是 useEffect Hook,它集 componentDidMount, componentDidUpdate, 和 componentWillUnmount 的功能于一身。
挂载 (Mounting) -> useEffect
模拟 componentDidMount,只需给 useEffect 传入一个空的依赖数组 []。
codeJsx
import React, { useState, useEffect } from 'react';
function MyComponent() {
const [data, setData] = useState(null);
// 这个 effect 只会在组件首次渲染后运行一次
useEffect(() => {
console.log('组件已挂载 (ComponentDidMount)');
// 在这里发起网络请求
fetch('api/data')
.then(res => res.json())
.then(setData);
// 添加事件监听
window.addEventListener('resize', handleResize);
}, []); // 空数组表示不依赖任何 props 或 state,所以只运行一次
return <div>...</div>;
}
更新 (Updating) -> useEffect
模拟 componentDidUpdate,只需在 useEffect 的依赖数组中放入需要监听的 props 或 state。
codeJsx
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
// 当 userId prop 发生变化时,这个 effect 会重新运行
useEffect(() => {
console.log(`组件已更新,因为 userId 变化了 (ComponentDidUpdate)`);
// 根据新的 userId 获取数据
fetch(`api/users/${userId}`)
.then(res => res.json())
.then(setUser);
}, [userId]); // 依赖数组中包含 userId
return <h1>{user ? user.name : 'Loading...'}</h1>;
}
卸载 (Unmounting) -> useEffect 的清理函数
模拟 componentWillUnmount,只需在 useEffect 的回调函数中返回一个清理函数。
codeJsx
function Timer() {
useEffect(() => {
const timerId = setInterval(() => {
console.log('Tick');
}, 1000);
// 返回一个清理函数
// 这个函数会在组件卸载前被调用
return () => {
console.log('组件将卸载,清理定时器 (ComponentWillUnmount)');
clearInterval(timerId);
};
}, []); // 空数组确保 effect 只运行一次,清理函数也只在卸载时运行
return <div>Timer is running...</div>;
}
总结与对比
| 生命周期阶段 | 类组件方法 | 函数组件 Hooks |
|---|---|---|
| 初始化 | constructor() | useState(), useRef() 等 Hooks 的调用 |
| 挂载后 (副作用) | componentDidMount() | useEffect(() => { ... }, []) |
| 更新后 (副作用) | componentDidUpdate() | useEffect(() => { ... }, [deps]) |
| 卸载前 (清理) | componentWillUnmount() | useEffect 返回的清理函数 () => { ... } |
| 性能优化 | shouldComponentUpdate() / PureComponent | React.memo(), useMemo(), useCallback() |
核心思想转变:
- 类组件:以时间点(挂载、更新、卸载)来组织代码。
- 函数组件 (Hooks) :以功能(数据获取、事件监听等)来组织代码。一个 useEffect 负责一个功能的副作用和清理,使得相关逻辑更加内聚。