React 生命周期分析

在 V16 版本中引入了 Fiber 机制。这个机制一定程度上的影响了部分生命周期的调用,并且也引入了新的 2 个 API 来解决问题。

在之前的版本中,如果你拥有一个很复杂的复合组件,然后改动了最上层组件的 state,那么调用栈可能会很长

React 生命周期分析 - 图1

调用栈过长,再加上中间进行了复杂的操作,就可能导致长时间阻塞主线程,带来不好的用户体验。Fiber 就是为了解决该问题而生。

Fiber 本质上是一个虚拟的堆栈帧,新的调度器会按照优先级自由调度这些帧,从而将之前的同步渲染改成了异步渲染,在不影响体验的情况下去分段计算更新。

React 生命周期分析 - 图2

对于如何区别优先级,React 有自己的一套逻辑。对于动画这种实时性很高的东西,也就是 16 ms 必须渲染一次保证不卡顿的情况下,React 会每 16 ms(以内) 暂停一下更新,返回来继续渲染动画。

对于异步渲染,现在渲染有两个阶段:reconciliationcommit 。前者过程是可以打断的,后者不能暂停,会一直更新界面直到完成。

Reconciliation 阶段

  • componentWillMount
  • componentWillReceiveProps
  • shouldComponentUpdate
  • componentWillUpdate

Commit 阶段

  • componentDidMount
  • componentDidUpdate
  • componentWillUnmount

因为 reconciliation 阶段是可以被打断的,所以 reconciliation 阶段会执行的生命周期函数就可能会出现调用多次的情况,从而引起 Bug。所以对于 reconciliation 阶段调用的几个函数,除了 shouldComponentUpdate 以外,其他都应该避免去使用,并且 V16 中也引入了新的 API 来解决这个问题。

getDerivedStateFromProps 用于替换 componentWillReceiveProps ,该函数会在初始化和 update 时被调用

  1. class ExampleComponent extends React.Component {
  2. // Initialize state in constructor,
  3. // Or with a property initializer.
  4. state = {};
  5. static getDerivedStateFromProps(nextProps, prevState) {
  6. if (prevState.someMirroredValue !== nextProps.someValue) {
  7. return {
  8. derivedData: computeDerivedState(nextProps),
  9. someMirroredValue: nextProps.someValue
  10. };
  11. }
  12. // Return null to indicate no change to state.
  13. return null;
  14. }
  15. }

getSnapshotBeforeUpdate 用于替换 componentWillUpdate ,该函数会在 update 后 DOM 更新前被调用,用于读取最新的 DOM 数据。

V16 生命周期函数用法建议

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