blog icon indicating copy to clipboard operation
blog copied to clipboard

Lifecycle after React 16.3

Open nanyang24 opened this issue 5 years ago • 0 comments

React 16.3 是比较重大的一次版本更新,涉及 新的lifecycle methods全新的Context ApiRef Api

详见官方文档

首先吸引到我的当然是生命周期的改变,就来简单谈一下,后面会写详细的帖子关于修改生命周期的原因

The New Lifecycle

涉及改变的三个 Lifecycle func:

  1. componentWillMount
  2. componentWillUpdate
  3. componentWillReceiveProps

在17.0版本之前,16.3版本开始,这三个 methods 将带有 UNSAFE_ 的前綴来标识,目的当然是为了让我们逐步的去修改项目中有关于这些Lifecycle func的代码,那 React 为了让我们更好的完成升级,也列出了建议:

componentWillMount

更换声明周期: componentWillMount ——> componentDidMount

这里有一个小问题,componentWillMount 似乎是请求数据方法的理想位置,所以有时候我们会将 请求后端的callback 写在其中,以求更早的请求数据(虽然我还没这么写过),但其实这样是误用

在组件的首次render之前会调用这个方法,所以在这个方法中 setState 不会发生重新渲染(re-render);

而且由于这是 Server side render 唯一的Lifecycle func,所以如果项目是基于SSR的,那 componentWillMount 很可能被调用很多次

BTW,在ES6的Class中,constructor() 可以作为 componentWillMount 的替代

componentWillUpdate

更换声明周期: componentWillUpdate ——> componentDidUpdate

这个很简单就不说啦

componentWillReceiveProps

这个可能是修改起来比较麻烦的一个了,使用的机会比较多,一般用作:

  1. 根据 Props来修改 State
  2. Props 改变时去调用一些Func,或者做出一些不会修改state的操作

针对第一种,更换方法:

componentWillReceiveProps ——> getDerivedStateFromProp

16.3 提出了一个新的静态方法:getDerivedStateFromProp Method Signature:

static getDerivedStateFromProps(nextProps, prevState) {
  // ...
}

注意这是一个静态方法,也就是说,在内部使用 this 是指向类的,而不是实例,所以无法使用 this.setState,那么如何更新状态呢?

其实只需要返回更新的状态就可以了,或是 null :表示state不需要更新

官方示例:

// before
componentWillReceiveProps(nextProps) {
  if (this.props.currentRow !== nextProps.currentRow) {
    this.setState({
      isScrollingDown: nextProps.currentRow > this.props.currentRow
    })
  }   
}

// after
static getDerivedStateFromProps(nextProps, prevState) {
  if (nextProps.currentRow !== prevState.lastRow) {
    return {
      isScrollingDown: nextProps.currentRow > prevState.lastRow,
      lastRow: nextProps.currentRow
    }
  }

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

通过例子可以得知,以往依赖比较 this.props.xxxnextProps.xxx 是不行了。在 getDerivedStateFromProps 中,需要将要比较的值也存到state当中,才能在之后通过 nextProps.xxx vs prevState.xxx 做比較

返回值的机制和使用 setState 的机制是类似的 —— 只需要返回发生改变的那部分状态,其他的值会保留。

针对第二种,使用 compomentDidUpdate

基本上在不更新state的情况下,使用这个methods来代替是完全可行的,因为包括了我们需要用的到prevProps,并且 componentDidUpdate 内部可以访问this.props,利用这两个我们可以作出各种比较

componentDidUpdate(prevProps, prevState) {
  if (this.props.reqPending !== prevProps.reqPending && !this.props.reqPending) {
     if(!this.props.error){
       this.props.history.push('/next-page')
     }
  }
}

总结

image

这张 React 16.3 生命周期来自于 Dan神 的twitter

详细介绍了 lifecycle methods 的执行顺序。

其实目前的16.4作出了一些小修改:

image

日后会写关于这个的帖子。

有个开发者将生命周期图做成动态的demo了,方便查询不同版本的差异 :链接

nanyang24 avatar Oct 17 '18 17:10 nanyang24