跳到主要内容

组件的生命周期

React 类组件的生命周期可分为 挂载阶段( Mounting )更新阶段( Updating )卸载阶段( Unmounting ),以及 React 16.3+ 新增的错误处理阶段( Error Handling )

一、挂载阶段(组件首次渲染到 DOM )

  • constructor():构造函数,初始化 state 或绑定事件处理函数(必须调用 super(props)
  • static getDerivedStateFromProps(props, state) (React 16.3 +):静态方法,在组件创建或更新前根据 props 更新 state (返回需合并的 state 对象或是 null
  • render():返回 JSX 描述的 UI 结构(纯函数,不修改状态或 DOM )
  • componentDidMount() :组件挂载后调用( DOM 已存在),适合执行副作用(如数据请求 、 定时器)

二、更新阶段(setState 或父组件重新渲染触发)

  • static getDerivedStateFromProps(props , state):同上,在更新前触发
  • shouldComponentUpdate(nextProps, nextState):返回布尔值,决定是否跳过更新(优化性能,比较 props/state 变化)
  • render():重新生成 UI 描述
  • getSnapshotBeforeUpdate(prevProps, prevState)React 16.3+):在 DOM 更新前捕获快照(如滚动位置),返回值传递给 componentDidUpdate
  • componentDidUpdate(prevProps, prevState, snapshot) : DOM 更新后调用(可执行副作用,如根据新的 props 重新请求数据)

三、卸载阶段(组件从 DOM 树移除)

  • componentWillUnmount():组件卸载前调用(清理定时器 、 取消网络请求 、 移除监听事件)

四、错误处理阶段(子组件渲染出错时)

  • static getDerivedStateFromError(error):静态方法,捕获子组件错误并更新 state(返回需合并的 state
  • componentDidCatch(error, info):记录错误信息(如上报日志)
注意

React 16.3+ 后废弃了 componentWillMountcomponentWillReceivePropscomponentWillUpdate (标记为 UNSAFE_ 前缀,推荐使用更安全的生命周期或 getDerivedStateFromProps 代替。

五、为什么 componentWillMount 被标记为不安全

React 18 中,componentWillMont 被标记为“不安全”( UNSAFE_ ),主要是为了配合 React 全新的 Fiber 结构并发渲染 模式。

简单来说,这个生命周期方法在旧版 React 中表现尚可,但在 React 18 的并发模式下,它可能会引发严重的副作用和不可预测的 Bug。

1. 核心原因: Fiber 架构与可中断的渲染

React 15 之前,渲染过程是同步且不可中断的。但在 React 16+ 引入的 Fiber 架构中,渲染过程被分为了两个阶段:

  • Render 阶段(渲染阶段) :主要是计算差异( Diff ),这个阶段是 可被中断、暂停甚至放弃的React 可能会因高优先级的任务(如用户点击)插队,而打断当前的渲染,稍后重新渲染
  • Commit 阶段(提交阶段) :将计算好的差异应用到 DOM 上,这个阶段是不可中断的,必须一气呵成以保证用户视觉连贯

componentWillMount 属于 Render 阶段。这意味着在 [React 18] 的并发模式下,他可能会被多次调用

举个栗子

如果 React 开始渲染组件 A (触发 componentWillMount ),但在提交到 DOM 之前被打断了,React 可能会丢弃这次渲染结果。当稍后重新渲染 A 时,componentWillMount 会再次执行

2. 具体带来的风险

由于 componentWillMount 可能会被执行多次,或者在渲染中中断执行,会导致以下严重问题:

  • 副作用重复执行 :如果在其中发起网络请求或甚至定时器,这些操作可能会重复发生,导致数据不一致或资源浪费
  • 内存泄漏与状态混乱 :这是一个非常隐蔽的 Bug。如果组件在 componentWillMont 中订阅了外部数据源,但随后的渲染被中断(即 componentDidMount 从未执行),那么组件虽然没有挂载成功,但订阅却建立了。由于 componentWillUnmount 只有在 componentDidMount 执行后才能保证调用,这将导致无法取消订阅,从而引发内存泄漏
  • 服务端渲染( SSR )问题 :在 SSR 环境中,componentWillMount 会在服务端执行一次,然后在客户端 hydration (注水)时再执行一次。如果涉及浏览器特有的 API(如 window 对象),会导致报错

3. 官方建议的代替方案

React 官方建议根据原本在 componentWillMount 中做的事情,将其拆分并迁移到更安全的地方:

原本在 componentWillMount 中操作推荐替代方案
初始化 State直接在 构造函数( constructor 中初始化,或使用类字段语法 state = {...}
订阅外部数据源/副作用移至 componentDidMount 。这是最安全的时机,因为它保证只执行一次且 DOM 已挂载
异步数据请求移至 componentDidMount 。虽然这可能会导致一次往外的渲染(先渲染空状态,再渲染数据),但能保证逻辑的健壮性