React-v17生命周期总结

2,200 阅读4分钟

本文整理 React v17中的生命周期,重新认识一下 React 生命周期。

React v17版本删除componentWillMount()componentWillReceiveProps()componentWillUpdate() 这三个函数,保留使用 UNSAFE_componentWillMount()UNSAFE_componentWillReceiveProps()UNSAFE_componentWillUpdate()

这张图是从👉react生命周期链接里找的,里面有可以根据react不同版本查看对应的生命周期函数。

1.生命周期总览

react的生命周期大概分为

  • 组件装载(Mount)组件第一次渲染到Dom树
  • 组件更新(update)组件state,props变化引发的重新渲染
  • 组件卸载(Unmount)组件从Dom树删除

2.组件装载(Mount)

  • constructor: 在此初始化state,绑定成员函数this环境,props本地化
  • getDerivedStateFromProps:在创建时或更新时的render之前执行,让 props 能更新到组件内部 state中。
  • render: 渲染函数,唯一的一定不能省略的函数,必须有返回值,返回null或false表示不渲染任何DOM元素。它是一个仅仅用于渲染的纯函数,返回值完全取决于this.state和this.props,不能在函数中任何修改props、state、拉取数据等具有副作用的操作。render函数返回的是JSX的对象,该函数并不因为这渲染到DOM树,何时进行真正的渲染是有React库决定的。
  • componentDidMount: 挂载成功函数。该函数不会再render函数调用完成之后立即调用,因为render函数仅仅是返回了JSX的对象,并没有立即挂载到DOM树上,而componentDidMount是在组件被渲染到DOM树之后被调用的。另外,componentDidMount函数在进行服务器端渲染时不会被调用。

3.组件更新(update)

当组件挂载到DOM树上之后,props/state被修改会导致组件进行更新操作。更新过程会以此调用如下的生命周期函数:

  • shouldComponentUpdate(nextProps, nextState):是否重新渲染组件 返回bool值,true表示要更新,false表示不更新,使用得当将大大提高React组件的性能,避免不需要的渲染。
  • getSnapshotBeforeUpdate:在render之后,React更新dom之前执行。它使您的组件可以在可能更改之前从DOM捕获一些信息(例如滚动位置),例如在聊天气泡页中用来计算滚动高度。它返回的任何值都将作为参数传递给componentDidUpdate()
  • render: 渲染函数
  • componentDidUpdate: 更新完成函数

4.组件卸载(Unmount)

  • componentWillUnmount:当React组件要从DOM树上删除前,会调用一次这个函数。这个函数经常用于去除componentDidMount函数带来的副作用,例如清除计时器清除事件监听

5.React V16.3 新增的生命周期方法

React v16.3虽然是一个小版本升级,但是却对React组件生命周期函数有巨大变化。

新增生命周期如下:

  • getDerivedStateFromProps
  • getSnapshotBeforeUpdate

同时废弃了以下生命周期:

  • componentWillReceiveProps
  • componentWillMount
  • componentWillUpdate

17 版本删除了 componentWillMount()componentWillReceiveProps()componentWillUpdate() 这三个函数,保留使用 UNSAFE_componentWillMount()UNSAFE_componentWillReceiveProps()UNSAFE_componentWillUpdate()

5.1 getDerivedStateFromProps(nextProps,prevState)

作用:

是为了让 props 能更新到组件内部 state中,它应返回一个对象来更新 state,如果返回 null 则不更新任何内容。

执行时机: 不论创建时还是更新时,都在render之前

特点:

  1. 是静态方法,内部的this指向的是类而非实例。所以不能通过this来访问class的属性。要保持其纯函数的特点,通过参数nextProsprevState来进行判断,根据新传入的props来映射state
  2. 没有内容更新的情况下也一定要返回一个null值,不然会报错。
static getDerivedStateFromProps(nextProps,prevState){
    // state无更新时return null
    return null;
}

5.2 getSnapshotBeforeUpdate(prevProps, prevState)

作用: 它使您的组件可以在可能更改之前从DOM捕获一些信息(例如滚动位置),在聊天气泡页中用来计算滚动高度。它返回的任何值都将作为参数传递给componentDidUpdate()

执行时机: 在render之后,可以读取但无法使用DOM的时候。

getSnapshotBeforeUpdate(prevProps, prevState) {
    // 捕获滚动的位置,以便后面进行滚动 注意返回的值
    if (prevProps.list.length < this.props.list.length) {
      const list = this.listRef.current;
      return list.scrollHeight - list.scrollTop;
    }
    return null;
}

举例: 举个在实际项目中使用此生命周期的例子,在聊天时的气泡页会遇到弹新的消息气泡场景,此时组件重新渲染了,如果不重新给外层包裹的dom计算滚动高度,会导致dom不停下滑。

在线demo: 👉getSnapshotBeforeUpdate例子

demo2.gif

而使用getSnapshotBeforeUpdate可以优化此场景。在getSnapshotBeforeUpdate生命周期中记录外层dom元素的高度perScrollHeight,在componentDidUpdate中重新计算外层dom的scrollTop。此时,页面滚动一段距离不会出现消息跳动的现象 👉优化后的例子

this.listRef.current.scrollTop = curScrollTop + (this.listRef.current.scrollHeight - perScrollHeight)

代码:👉github代码

6. 不能使用setState的生命周期

其中打×的是不能使用setState的,打 的是能用setState的。

promise.jpeg

7.小结

屏幕快照 2021-05-06 下午4.55.38.png