React —— React生命周期的简单对比

194 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第1天,点击查看活动详情

React生命周期的简单对比

一、不同版本React生命周期图示

1. 旧版React生命周期 —— React < V16

image.png

图片来源文章

2. 新版React生命周期 —— React >= V16

注意 V16.3 和 V16.4 之间有细微的区别,主要是在static get­Derived­State­From­Props的触发时机上

image.png

image.png

在线演示项目

二、React 16+ 版本之后有哪些变化?

1. 简而言之

移除(添加声明UNSAFE)

- UNSAFE_componentWillMount
- UNSAFE_componentWillReceiveProps
- UNSAFE_componentWillUpdate

新增

+ getDerivedStateFromProps
+ getSnapshotBeforeUpdate

2.为什么要作出这些变化?

React V16 引入了 Fiber 机制

Fiber 是 React V16 对 React 核心算法的一次重写,简单的理解就是 Fiber 会使原本同步的渲染过程变成增量渲染模式。Fiber带来了两个重要的新特性:任务分解 与 渲染过程可打断。Fiber 机制更详细的介绍之后可能会新起一篇文章,这里主要是说一下Fiber 机制对旧版生命周期的影响。

从上面的图示可以看出,React生命周期大致可以分为三个阶段

  • render 阶段:Pure and has no side effects. May be paused, aborted or restarted by React.

  • pre-commit 阶段:Can read the DOM.

  • commit 阶段:Can work with DOM, run side effects, schedule updates.

    render 阶段 在执行过程中允许被打断和重启,
    commit 阶段( 包括 pre-commit )则总是同步执行,一直更新界面直到完成。

在旧版生命周期中

Render 阶段

  • componentWillMount
  • componentWillReceiveProps
  • shouldComponentUpdate
  • componentWillUpdate

Commit 阶段

  • componentDidMount
  • componentDidUpdate
  • componentWillUnmount

可以发现,在旧版生命周期中, componentWillMount, componentWillReceiveProps, componentWillUpdate,都是处于render 阶段,可能会被打断或者重启多次,从而导致一些不可预测的bug,所以应该避免去使用。

相应地,React V16 新增了两个新的生命周期函数来解决这个问题

  • getDerivedStateFromProps:用于替换 componentWillReceiveProps
  • getSnapshotBeforeUpdate:用于替换 componentWillUpdate

三、React V16 生命周期函数用法建议


class ExampleComponent extends React.Component {
  // 用于初始化 state
  constructor() {}
  
  // 用于替换 `componentWillReceiveProps` ,该函数会在初始化和 `update` 时被调用
  // 因为该函数是静态函数,所以取不到 `this`
  // 如果需要对比 `prevProps` 需要单独在 `state` 中维护
  static getDerivedStateFromProps(nextProps, prevState) {}
  
  // 判断是否需要更新组件,多用于组件性能优化
  shouldComponentUpdate(nextProps, nextState) {}
  
  // 组件挂载后调用
  // 可以在该函数中进行请求或者订阅
  componentDidMount() {}
  
  // 用于获得最新的 DOM 数据
  getSnapshotBeforeUpdate() {}
  
  // 组件即将销毁
  // 可以在此处移除订阅,定时器等等
  componentWillUnmount() {}
  
  // 组件销毁后调用
  componentDidUnMount() {}
  
  // 组件更新后调用
  componentDidUpdate() {}
  
  // 渲染组件函数
  render() {}
  
  // 以下函数不建议使用
  UNSAFE_componentWillMount() {}
  UNSAFE_componentWillUpdate(nextProps, nextState) {}
  UNSAFE_componentWillReceiveProps(nextProps) {}
  
}

四、 一些需要注意的问题

1. static getDerivedStateFromProps

getDerivedStateFromProps 是一个静态方法,静态方法存在于组件类上,不依赖于组件的实例而存在。所以应该避免在静态方法内部读取 this 对象。

2. getDerivedStateFromProps的返回值

需要从Props派生新的State:返回一个对象用来更新state
不需要更新state:返回 null


static getDerivedStateFromProps(nextProps, prevState) {
    if (prevState.someMirroredValue !== nextProps.someValue) {
      return {
        derivedData: computeDerivedState(nextProps),
        someMirroredValue: nextProps.someValue
      }
    }

    // Return null to indicate no change to state.
    return null
  }
  

3. 生命周期方法与 Hook 的对应

生命周期方法要如何对应到 Hook?