react16-react19类组件完整生命周期(挂载/更新/卸载)

React16 ~ React19 类组件完整生命周期(挂载 / 更新 / 卸载)

React 类组件生命周期在 React16 之后变化非常大:

  • React15:旧生命周期

  • React16:引入 Fiber 架构

  • React16.3:新增安全生命周期

  • React17:基本延续 React16

  • React18:并发特性开始影响生命周期调用

  • React19:类组件仍支持,但官方主推函数组件 Hooks

下面我按:

  1. 生命周期总览

  2. 挂载阶段

  3. 更新阶段

  4. 卸载阶段

  5. 错误处理阶段

  6. React16~19变化对比

  7. 执行顺序图

  8. 面试高频点

完整讲透。


一、React 类组件生命周期总览

React16+ 生命周期:

复制代码
挂载 Mounting
	constructor
	static getDerivedStateFromProps
	render
	componentDidMount

更新 Updating
	static getDerivedStateFromProps
	shouldComponentUpdate
	render
	getSnapshotBeforeUpdate
	componentDidUpdate

卸载 Unmounting
	componentWillUnmount

错误处理 Error Handling
	static getDerivedStateFromError
	componentDidCatch

二、React16 之前旧生命周期(了解)

React16.3 之前:

复制代码
componentWillMount
componentWillReceiveProps
componentWillUpdate

后来因为:

  • 异步渲染不安全

  • 容易造成副作用

  • Concurrent Mode 会重复执行

所以被废弃。

React16.3 开始:

复制代码
UNSAFE_componentWillMount
UNSAFE_componentWillReceiveProps
UNSAFE_componentWillUpdate

React17+ 不推荐使用。

React19 依然还能用,但属于遗留 API。


三、挂载阶段(Mounting)

组件第一次进入页面。


1.constructor

组件初始化。

复制代码
class Demo extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      count: 0
    }
  }
}

作用:

  • 初始化 state

  • 绑定 this

  • 创建 ref

注意:

❌ 不要:

复制代码
this.setState()

因为组件还没挂载。


执行顺序:

复制代码
new 组件实例
↓
constructor

2.static getDerivedStateFromProps

React16.3 新增。

用于:

  • 根据 props 派生 state

    static getDerivedStateFromProps(props, state) {
    if (props.count !== state.count) {
    return {
    count: props.count
    }
    }

    复制代码
    return null

    }

特点:

  • 静态方法

  • 没有 this

  • 必须 return object/null


执行时机:

复制代码
初始化
+
props更新
都会执行

注意:

这是:

复制代码
render前
最后一次修改state机会

不推荐滥用。

很多场景:

复制代码
props -> 直接使用

不需要同步到 state。


3.render

必须实现。

复制代码
render() {
  return <div>Hello</div>
}

作用:

  • 返回 JSX

  • 生成 Virtual DOM

特点:

必须纯函数:

❌ 不允许:

复制代码
ajax
setTimeout
setState
操作DOM

因为 render 可能重复执行。


4.componentDidMount

组件挂载完成。

复制代码
componentDidMount() {
  console.log('mounted')
}

执行时机:

复制代码
真实DOM完成后

这里最适合:

✅ 请求接口

复制代码
axios.get()

✅ 操作 DOM

复制代码
this.ref.current.focus()

✅ 开启定时器

复制代码
setInterval()

✅ 初始化图表

复制代码
echarts.init()

完整挂载顺序:

复制代码
constructor
↓
getDerivedStateFromProps
↓
render
↓
componentDidMount

四、更新阶段(Updating)

触发更新:

复制代码
1. props变化
2. setState
3. forceUpdate

更新生命周期总流程

复制代码
getDerivedStateFromProps
↓
shouldComponentUpdate
↓
render
↓
getSnapshotBeforeUpdate
↓
componentDidUpdate

1.getDerivedStateFromProps

更新时也会执行。

复制代码
static getDerivedStateFromProps(props, state)

作用:

根据新的 props 更新 state。


2.shouldComponentUpdate

性能优化核心。

复制代码
shouldComponentUpdate(nextProps, nextState) {
  return true
}

返回值:

复制代码
true  -> 继续更新
false -> 阻止更新

优化例子:

复制代码
shouldComponentUpdate(nextProps, nextState) {
  return nextState.count !== this.state.count
}

React 提供:

复制代码
PureComponent

自动浅比较。

等价于:

复制代码
shouldComponentUpdate + shallowCompare

3.render

重新生成 Virtual DOM。


4.getSnapshotBeforeUpdate

React16.3 新增。

在:

复制代码
DOM更新前

获取 DOM 快照。

复制代码
getSnapshotBeforeUpdate(prevProps, prevState) {
  return this.container.scrollHeight
}

返回值会传给:

复制代码
componentDidUpdate

典型场景:

聊天窗口滚动位置。


执行时机:

复制代码
render之后
真实DOM更新之前

5.componentDidUpdate

更新完成。

复制代码
componentDidUpdate(prevProps, prevState, snapshot) {

}

参数:

复制代码
prevProps
prevState
snapshot

适合:

✅ ajax重新请求

✅ DOM操作

✅ 第三方库更新


注意:

必须加条件。

复制代码
componentDidUpdate() {
  this.setState({})
}

会无限循环。

正确:

复制代码
componentDidUpdate(prevProps) {
  if (prevProps.id !== this.props.id) {
    this.setState({})
  }
}

五、卸载阶段(Unmounting)


componentWillUnmount

组件销毁前。

复制代码
componentWillUnmount() {
  clearInterval(this.timer)
}

作用:

✅ 清除定时器

✅ 取消订阅

✅ 移除事件监听

✅ 销毁实例


典型:

复制代码
window.removeEventListener()

echarts.dispose()

注意:

组件即将销毁:

❌ 不要:

复制代码
this.setState()

六、错误处理生命周期(Error Boundaries)

React16 新增。


1.static getDerivedStateFromError

发生错误时更新 UI。

复制代码
static getDerivedStateFromError(error) {
  return {
    hasError: true
  }
}

2.componentDidCatch

捕获错误日志。

复制代码
componentDidCatch(error, info) {
  console.log(error)
}

典型:

复制代码
错误监控
Sentry
日志平台

七、React16~19 生命周期变化


React16

重大变化:

✅ Fiber架构

新增:

复制代码
getDerivedStateFromProps
getSnapshotBeforeUpdate
componentDidCatch

废弃:

复制代码
componentWillMount
componentWillReceiveProps
componentWillUpdate

React17

基本无生命周期变化。

主要:

复制代码
为React18铺路

React18

并发渲染开始影响生命周期。

开发模式 StrictMode:

某些生命周期会执行两次。

例如:

复制代码
constructor
render
componentDidMount

原因:

检测副作用。

不是 bug。


例如:

复制代码
<React.StrictMode>
  <App />
</React.StrictMode>

开发环境可能:

复制代码
mount
unmount
再mount

React19

React19:

  • 类组件仍支持

  • 生命周期仍可用

  • 官方全面推荐 Hooks

未来趋势:

复制代码
类组件 -> 维护旧项目
函数组件 -> 主流

八、完整生命周期执行顺序图


首次挂载

复制代码
constructor
↓
getDerivedStateFromProps
↓
render
↓
componentDidMount

更新阶段

复制代码
getDerivedStateFromProps
↓
shouldComponentUpdate
↓
render
↓
getSnapshotBeforeUpdate
↓
componentDidUpdate

卸载阶段

复制代码
componentWillUnmount

错误阶段

复制代码
getDerivedStateFromError
↓
componentDidCatch

九、废弃生命周期执行顺序(旧项目)

旧版:

复制代码
componentWillMount
render
componentDidMount

更新:

复制代码
componentWillReceiveProps
shouldComponentUpdate
componentWillUpdate
render
componentDidUpdate

React16.3后:

复制代码
UNSAFE_componentWillMount
UNSAFE_componentWillReceiveProps
UNSAFE_componentWillUpdate

十、完整生命周期代码示例

复制代码
class Demo extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      count: 0
    }

    console.log('constructor')
  }

  static getDerivedStateFromProps(props, state) {
    console.log('getDerivedStateFromProps')
    return null
  }

  shouldComponentUpdate(nextProps, nextState) {
    console.log('shouldComponentUpdate')
    return true
  }

  render() {
    console.log('render')

    return (
      <div>
        {this.state.count}

        <button
          onClick={() => {
            this.setState({
              count: this.state.count + 1
            })
          }}
        >
          +
        </button>
      </div>
    )
  }

  componentDidMount() {
    console.log('componentDidMount')
  }

  getSnapshotBeforeUpdate(prevProps, prevState) {
    console.log('getSnapshotBeforeUpdate')

    return 'snapshot'
  }

  componentDidUpdate(prevProps, prevState, snapshot) {
    console.log('componentDidUpdate', snapshot)
  }

  componentWillUnmount() {
    console.log('componentWillUnmount')
  }

  static getDerivedStateFromError(error) {
    return {
      hasError: true
    }
  }

  componentDidCatch(error, info) {
    console.log(error, info)
  }
}

十一、面试高频问题


1.render 能 setState 吗?

不能。

会死循环。


2.componentDidMount 为什么适合请求接口?

因为:

复制代码
DOM已存在
不会阻塞首次渲染

3.shouldComponentUpdate 有什么用?

性能优化。

减少无意义 render。


4.getSnapshotBeforeUpdate 用在哪?

获取 DOM 更新前状态。

典型:

复制代码
滚动条位置

5.为什么废弃 componentWillXXX?

因为:

复制代码
异步渲染不安全
可能重复执行

6.React18 为什么生命周期执行两次?

StrictMode 检测副作用。

仅开发环境。


十二、React16~19 生命周期脑图(简版)

复制代码
挂载
 constructor
 ↓
 getDerivedStateFromProps
 ↓
 render
 ↓
 componentDidMount

更新
 getDerivedStateFromProps
 ↓
 shouldComponentUpdate
 ↓
 render
 ↓
 getSnapshotBeforeUpdate
 ↓
 componentDidUpdate

卸载
 componentWillUnmount

错误
 getDerivedStateFromError
 ↓
 componentDidCatch
相关推荐
whinc2 小时前
Node.js技术周刊 2026年第14周
javascript·node.js
这个昵称也不能用吗?3 小时前
eas 热更新相关
前端
KaMeidebaby3 小时前
卡梅德生物技术快报|葫芦科植物遗传转化:Fast‑TrACC 工程化优化:葫芦科植物遗传转化效率提升与成本控制
前端·其他·百度·新浪微博
换日线°3 小时前
vue 加入购物车抛物线动画
前端·javascript·vue.js
切糕师学AI4 小时前
为什么你的 SPA 网址必须包含 `#`?—— 前端路由 Hash 模式深度解析
前端·spa 网址·hash路由
冴羽4 小时前
超越Vibe Coding —— AI 辅助编程进阶指南
前端·javascript·ai编程
流氓也是种气质 _Cookie4 小时前
Chrome Performance常见名词解释(FP, FCP, LCP, DCL, FMP, TTI, TBT, FID, CLS)
开发语言·javascript·ecmascript
MXN_小南学前端4 小时前
自制和整理常用前端 AI Skills分享,从需求到页面(附github地址)
前端·ai编程
yuki_uix4 小时前
双 RAF + MutationObserver:微前端跳转后的滚动复原完整方案
前端