04-React生命周期

参考:
- React 官网:https://zh-hans.react.dev/
- React 教程:https://zh-hans.react.dev/learn
1. 生命周期
v17 & v19
组件的生命周期可分成三个状态:
- Mounting(挂载|初始化):已插入真实 DOM (constructor
→render→componentDidMount) - Updating(更新|运行中):正在被重新渲染 (render
→componentDidUpdate) - Unmounting(卸载|销毁):已移出真实 DOM (componentWillUnmount)

| 生命周期 | 具体方法 | React 17 支持情况 | React 19 支持情况 | 核心说明 |
|---|---|---|---|---|
| 挂载阶段 | constructor |
✅ 完全支持 | ✅ 完全支持 | 初始化 state / 绑定事件,17/19 用法一致 |
static getDerivedStateFromProps |
✅ 支持(慎用) | ✅ 支持(功能不变) | 极少使用,17/19 均不推荐(用 Hooks 替代) | |
render |
✅ 核心支持 | ✅ 核心支持 | 渲染 UI,17/19 完全一致 | |
componentDidMount |
✅ 核心支持 | ✅ 完全支持 | 挂载后执行(请求数据 / 操作 DOM),通用 | |
| 更新阶段 | static getDerivedStateFromProps |
✅ 支持 | ✅ 支持 | 同上 |
shouldComponentUpdate |
✅ 支持(性能优化) | ✅ 完全支持 | 控制是否重渲染,通用 | |
render |
✅ 核心支持 | ✅ 核心支持 | 同上 | |
getSnapshotBeforeUpdate |
✅ 支持(极少用) | ✅ 支持 | 更新前获取 DOM 快照,17/19 均极少使用 | |
componentDidUpdate |
✅ 核心支持 | ✅ 完全支持 | 更新后执行(更新 DOM / 请求数据),通用 | |
| 卸载阶段 | componentWillUnmount |
✅ 核心支持 | ✅ 完全支持 | 卸载前清理(取消请求 / 移除监听),通用 |
| 错误处理 | componentDidCatch |
✅ 支持 | ✅ 完全支持 | 捕获子组件错误,通用 |
| 过时 / 不安全 API | UNSAFE_componentWillMount |
✅ 支持(带警告) | ❌ 彻底移除 | 17 中已标记 UNSAFE,19 直接移除,改用 componentDidMount |
UNSAFE_componentWillReceiveProps |
✅ 支持(带警告) | ❌ 彻底移除 | 17 中已标记 UNSAFE,19 移除,改用 getDerivedStateFromProps 或 Hooks |
|
UNSAFE_componentWillUpdate |
✅ 支持(带警告) | ❌ 彻底移除 | 17 中已标记 UNSAFE,19 移除,改用 getSnapshotBeforeUpdate 或 Hooks |
|
| 废弃 API | componentDidCatch 的第二个参数 errorInfo |
✅ 支持 | ✅ 支持,但 React 19 推荐用 useErrorBoundary(Hooks)替代 |
类组件仍可用,19 更推荐 Hooks 写法 |
老的生命周期的问题:
(1) componentWillMount, 在ssr中这个方法将会被多次调用,所以会重复触发多遍,同时在这里如果绑定事件,将无法解绑,导致内存泄漏,变得不够安全高效逐步废弃。
(2) componentWillReceiveProps,外部组件多次频繁更新传入多次不同的 props,会导致不必要的异步请求
(3) componetWillupdate, 更新前记录 DOM 状态, 可能会做一些处理,与componentDidUpdate相隔时间如果过长,会导致状态不太信
1.1【挂载】(1/3)
顺序:
①contructor
contructor- 构造函数- 应用:初始化 state、绑定 this、绑定事件处理函数、
1 | |
效果:

componentWillMount-废弃
componentWillMount- render 之前最后一次修改状态的机会 (v19移除,改用componentDidMount)
②getDerivedStateFromProps-新
static getDerivedStateFromProps- 在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用。- 应用:子组件 State 依赖父组件 Props,且需随 Props 自动更新
- 说么:极少使用,v17/v19 均不推荐(用 Hooks 替代)
③render
render- 必须实现,只能访问 this.props 和 this.state ,不允许直接修改状态和DOM输出
④componentDidMount
componentDidMount- 成功 render 并渲染完成真实 DOM 之后触发,可以修改 DOM,初始化DOM,只执行一次- 应用:axios数据请求、事件监听、订阅函数调用、setInterval、基于创建完的DOM进行初始化如 BetterScroll 等
1 | |
输出:
1 | |
案例:better-scroll 使用
1 | |
1.2【更新】(2/3)
componentWillReceiveProps-废弃
componentWillReceiveProps- 父组件修改属性触发子组件中该属性方法 (v19 移除,改用getDerivedStateFromProps或 Hooks)
①getDerivedStateFromProps-新
static getDerivedStateFromProps- 在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用。- 应用:子组件 State 依赖父组件 Props,且需随 Props 自动更新
- 说么:极少使用,v17/v19 均不推荐(用 Hooks 替代)
1 | |
效果:

②shouldComponentUpdate
shouldComponentUpdate(nextProps, nextState, nextContext)- SCU,逻辑判断返回 false ,以阻止 render 重复渲染调用应用:性能优化(阻止无意义重渲染),多用在子组件中
对象判断前后 state 是否有差异(状态字段较多的情况):
- ```js
if (JSON.stringify(this.state) !== JSON.stringify(nextState)) {
return true
}
return false1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
```js
import React from 'react'
// 子组件:控制仅当 username 变化时才重渲染
class UserItem extends React.Component {
// 核心:判断是否需要重渲染
shouldComponentUpdate(nextProps, nextState) {
// 仅当新Props的username和当前Props不同时,才允许重渲染
return nextProps.username !== this.props.username
}
render() {
// 打印渲染日志,验证是否触发重渲染
console.log('UserItem 渲染了')
return <div>用户名:{this.props.username}</div>
}
}
// 父组件:控制传递的Props和自身State
class Parent extends React.Component {
state = {
username: '张三',
count: 0, // 无关状态,仅用于测试
}
// 点击按钮仅修改count(不影响子组件)
changeCount = () => {
this.setState(prev => ({ count: prev.count + 1 }))
}
// 点击按钮修改username(影响子组件)
changeName = () => {
this.setState({ username: '李四' })
}
render() {
return (
<div>
<p>计数:{this.state.count}</p>
<button onClick={this.changeCount}>修改计数(不触发子组件渲染)</button>
<button onClick={this.changeName}>修改用户名(触发子组件渲染)</button>
{/* 子组件仅接收username Props */}
<UserItem username={this.state.username} />
</div>
)
}
}
export default Parent
- ```js
效果:

③render
render- 必须实现,只能访问 this.props 和 this.state ,不允许直接修改状态和DOM输出
componentWillUpdate-废弃
componentWillUpdate- 在 DOM 更新前(render 之后、真实 DOM 刷新前)执行,不能修改属性和状态 (v19 移除,改用getSnapshotBeforeUpdate(prevProps, prevState)或 Hooks)- 应用:记录 DOM 更新前状态(如滚动位置)
④getSnapshotBeforeUpdate-新
getSnapshotBeforeUpdate- 在最近一次渲染输出(提交到 DOM 节点)之前调用。- 应用:捕获 DOM 更新前的状态(如滚动位置),更新后恢复该状态
- 注意:该方法极少用,仅在「需要获取 DOM 更新前状态」时使用,React 19 中仍兼容,但函数组件可通过
useRef+useEffect实现等价逻辑
1 | |
效果:

⑤componentDidUpdate
componentDidUpdate(prevProps, prevState, snapshot)- 可以修改 DOM,会多次执行,需要对多次执行进行判断以限制- 应用:依赖 props/state 变化的二次请求、DOM 更新
1 | |
输出:
1 | |
案例:阻止重复渲染
1 | |
效果:

1.3【卸载】(3/3)
①componentWillUnmount
componentWillUnmount- 在删除组件之前进行清理操作,比如计时器和事件监听器- 应用:取消请求、移除事件监听、清理定时器、置空回收如window.onresize=null
1 | |
1.4 错误处理
componentDidCatch
componentDidCatch- 捕获子组件错误,通用- 应用:捕获子组件错误、上报错误日志、兜底展示错误 UI避免整个应用白屏崩溃
1 | |
效果:

2. 性能优化
2.1 shouldComponentUpdate
SCU,控制组件自身或者子组件是否需要更新,尤其在子组件非常多的情况下,需要进行优化。
2.2 PureComponent
PureComponent 会帮你比较新props 跟旧的props,新的state和老的state(值相等,或者对象含有相同的属性、且属性值相等),决定shouldcomponentUpdate 返回true 或者false,从而决定要不要调用 render 去重新渲染。
注意:如果你的 state 或 props 『永远都会变』,那 PureComponent 并不会比较快,因为 shallowEqual 也需要花时间。
1 | |
案例:React 封装 Swiper 轮播
安装:npm i swiper@8 - 以大版本 8 为例
验证
1 | |
封装
目录:
1 | |
index.js
1 | |
swiper/Swiper.js
1 | |
swiper/SwiperItem.js
1 | |
效果:
