React生命周期

React 在V16版本中,分别废弃和新增了一些生命周期的钩子函数

新旧生命周期对比

old lifecycle

挂载:

  • constructor
  • componentWillMount
  • render
  • componentDidMount

更新:

  • componentWillReceiveProps
  • shouldComponentUpdate
  • componentWillUpdate
  • render
  • componentDidUpdate

卸载:

  • componentWillUnmount

new lifecycle(React v16.4)

挂载:

  • constructor
  • getDeviedStateFromProps
  • render
  • componentDidMount

更新:

  • getDeviedStateFromProps
  • shouldComponentUpdate
  • render
  • getSnapshotBeforeUpdate
  • componentDidUpdate

卸载:

  • componentWillUnmount

React 在v16.3版本中将 componentWillMount, componentWillReceiveProps 以及componentWillUpdate 加上了UNSAFE_前缀,这些钩子将在React 17.0废除:

  • UNSAFE_componentWillMount
  • UNSAFE_componentWillReceiveProps
  • UNSAFE_componentWillUpdate

同时React引入两个钩子函数来替代它们,分别是:

  • getDerivedStateFromProps
  • getSnapshotBeforeUpdate

为什么要这么做

  • componentWillMount

该钩子在页面初始化render之前会执行一次或多次(async rendering)

并且这个钩子完全可以使用componentDidMount和constructor来代替

  • componentWillReceiveProps

在老版本的 React 中,如果组件自身的某个 state 跟其 props 密切相关的话,一直都没有一种很优雅的处理方式去更新 state,而是需要在 componentWillReceiveProps 中判断前后两个 props 是否相同,如果不同再将新的 props 更新到相应的 state 上去。这样做一来会破坏 state 数据的单一数据源,导致组件状态变得不可预测,另一方面也会增加组件的重绘次数。类似的业务需求也有很多,如一个可以横向滑动的列表,当前高亮的 Tab 显然隶属于列表自身的状态,但很多情况下,业务需求会要求从外部跳转至列表时,根据传入的某个值,直接定位到某个 Tab

为了解决这些问题,React引入了一个新的生命周期: static getDerivedStateFromProps(nextProps, prevState) //返回一个对象 和调用setState一样

  • componentWillUpdate

与 componentWillReceiveProps 类似,许多开发者也会在 componentWillUpdate 中根据 props 的变化去触发一些回调。但不论是 componentWillReceiveProps 还是 componentWillUpdate,都有可能在一次更新中被调用多次,也就是说写在这里的回调函数也有可能会被调用多次,这显然是不可取的。与 componentDidMount 类似,componentDidUpdate 也不存在这样的问题,一次更新中 componentDidUpdate 只会被调用一次,所以将原先写在 componentWillUpdate 中的回调迁移至 componentDidUpdate 就可以解决这个问题

  • static getDerivedStateFromProps(nextProps, prevState)

在 render 前调用,在初始挂载以及后续更新时都会被调用

返回值:返回一个对象来更新 state, 如果返回 null 则不更新任何内容

需要注意的是,getDerivedStateFromProps 是一个静态函数,不能使用this, 也就是只能作一些无副作用的操作,每当父组件引发当前组件的渲染过程时,getDerivedStateFromProps会被调用,这样我们有一个机会可以根据新的props和之前的state来调整新的state

1
2
3
static getDerivedStateFromProps(nextProps, prevState) {
//根据nextProps和prevState计算出预期的状态改变,返回结果会被送给setState
}
  • getSnapshotBeforeUpdate(prevProps, prevState)

这函数会在render之后执行,而执行之时DOM元素还没有被更新,给了一个机会去获取DOM信息,计算得到一个snapshot,这个snapshot会作为componentDidUpdate的第三个参数传入

1
2
3
4
5
6
7
8
getSnapshotBeforeUpdate(prevProps, prevState) {
console.log('#enter getSnapshotBeforeUpdate');
return 'foo';
}

componentDidUpdate(prevProps, prevState, snapshot) {
console.log('#enter componentDidUpdate snapshot = ', snapshot);
}