「React」问:为什么React16要更改生命周期

316 阅读3分钟

React15生命周期汇总

初始化

constructor

挂载阶段

componentWillMount → render → componentDidMount

更新阶段

  • componentWillReceiveProps props更新才会触发的生命周期
  • **shouldComponentUpdate **
  • componentWillUpdate
  • render
  • componentDidUpdate

卸载阶段

componentsWillUnmount

React 16生命周期汇总

挂载阶段

  • constructor
  • static getDerivedStateFromProps(props,state)
  • render
  • componentDidMount

更新阶段

  • static getDerivedStateFromProps(props,state)
  • **shouldComponentUpdate **
  • render
  • getSnapotBeforeUpdate
  • componentDidUpdate

卸载阶段

  • componentsWillUnmount

生命周期的变更

componentWillMount,componentWillReceiveProps,componentWillUpdate 标记为unSafe

引入getDerivedStateFromPropsgetSnapshotBeforeUpdate

在render阶段之前是不能处理副作用的,因为可能会被react重新暂停,终止或者重新启用。

React16.4在render之前的三个生命周期函数

constructor,getDerivedStateFromProps,shouldComponentUpdate

getDerivedStateFromProps

它不是 componentWillMount 的替代品,而是试图替换掉 componentWillReceiveProps,但它又不能完全替换,因为它有且仅有一个用途:使用 props 来派生/更新 state,如果你不是出于这个目的来使用 getDerivedStateFromProps,原则上来说都是不符合规范的。

它内部没有this,所有不能执行更新状态等可能引起副作用的操作。

简化生命周期功能的做法也是为了确保生命周期函数的行为更加可控以及可预测。

  • 它应该返回一个对象来更新状态,或者返回null来不更新任何内容。
  • this为undefined,因为静态方法没有实例化
  • 确保使用的时候是通过 props的变化来派生/更新 state。

getSnapshotBeforeUpdate

它接受两个参数 prevProps, prevState,都是上一次props和state。

返回值会作为第三个参数给到 componentDidUpdate

它的执行时机是在 render 方法之后,真实 DOM 更新之前。在这个阶段里,我们可以同时获取到更新前的真实 DOM 和更新前后的 state&props 信息。

为什么componentWillMount 一定要废除?

Fiber 架构的重要特征就是可以被打断的异步渲染模式。但这个“打断”是有原则的,根据“能否被打断”这一标准,React 16 的生命周期被划分为了 render 和 commit 两个阶段,而 commit 阶段又被细分为了 pre-commit 和 commit。

  • render 阶段:纯净且没有副作用,可能会被 React 暂停、终止或重新启动。
  • pre-commit 阶段:可以读取 DOM。
  • commit 阶段:可以使用 DOM,运行副作用,安排更新。

总的来说,render 阶段在执行过程中允许被打断,而 commit 阶段则总是同步执行的。

在 Fiber 机制下,render 阶段是允许暂停、终止和重启的。当一个任务执行到一半被打断后,下一次渲染线程抢回主动权时,这个任务被重启的形式是“重复执行一遍整个任务”而非“接着上次执行到的那行代码往下走”。这就导致 render 阶段的生命周期都是有可能被重复执行的。

React 16 要废除的三个生命周期函数都是属于render阶段的,都可能会被重复执行,而且这些生命周期函数经常被滥用,所以在重复执行的过程都存在着难以预估的风险。