用惯了vue用react的生命周期总有一丝怪异啊,不过这并不妨碍我记点笔记

生命周期仅存在于类组件中,函数组件每次调用都是重新运行函数,旧的组件会被立刻销毁

旧版生命周期

总览

旧版生命周期对应React的版本小于16.3
file

constructor(props, context, updater)

React借用class类的constructor充当初始化钩子。

React规定constructor有三个参数,分别是props、context和updater。

  • props是属性,它是不可变的。
  • context是上下文
  • updater是包含一些更新方法的对象,this.setState最终调用的是this.updater.enqueueSetState方法,this.forceUpdate最终调用的是this.updater.enqueueForceUpdate方法,所以这些API更多是React内部使用,暴露出来是以备开发者不时之需。

在React中,constructor需要先调用super(props),用于初始化this和props,详情可以看这里

constructor生命周期钩子中可以初始化this.state。

也可以使用下面的代码初始化state

1
2
3
4
5
6
7
8
9
import React, { Component } from 'react';

class App extends Component {
state = {
name: 'biu',
};
}

export default App;

constructor只会在组件创建时调用一次,之后的组件更新不会再调用constructor

componentWillMount()

这是组件挂载到DOM之前的生命周期钩子。

在某些特殊情况下,这个函数有可能会被调用两次,

  • 服务端渲染
  • Fiber的Reconciliation过程中打断了这个生命周期

所以有可能出现一些bug,不过这个生命周期好像也没什么用,所以建议尽量不要使用

render()

作为一个组件,最核心的功能就是把元素挂载到DOM上,所以render生命周期钩子是一定会用到的。

render会返回一个虚拟DOM,这个虚拟DOM会被挂载到虚拟DOM树中,最终渲染到页面的真实DOM中

render可能不只运行一次,只要需要重新渲染,就会重新运行

在render中最好不要使用setState,因为可能会导致无限递归渲染

componentDidMount()

这是组件挂载到DOM之后的生命周期钩子,这个时候的组件已经就绪,你可以随心所欲的操作数据了

通常情况下,我们会将网络请求、启动计时器等初始化操作,书写到该函数中

componentWillReceiveProps(nextProps)

componentWillReceiveProps生命周期钩子只有一个参数,即更新后的props,这个生命周期不会在组件初始化时触发

该声明周期函数可能在两种情况下被触发:

  • 组件接收到了新的属性。
  • 组件没有收到新的属性,但是由于父组件重新渲染导致当前组件也被重新渲染。

同样,因为Fiber机制的引入,这个生命周期钩子有可能会多次触发。

shouldComponentUpdate(nextProps, nextState)

这个生命周期钩子用于指示React是否要重新渲染该组件(通过返回true或者false), 主要用于性能优化

shouldComponentUpdate生命周期钩子默认返回true。也就是说,默认情况下,只要组件触发了更新,组件就一定会更新。

如果开发者调用this.forceUpdate强制更新,React组件会无视这个钩子

componentWillUpdate(nextProps, nextState)

组件即将被重新渲染时调用这个钩子,具体来说是在shouldComponentUpdate生命周期钩子返回true,或者调用this.forceUpdate之后。

在componentWillUpdate中最好不要使用setState,因为可能会导致无限递归渲染

同样,因为Fiber机制的引入,这个生命周期钩子有可能会多次调用。

componentDidUpdate(nextProps, nextState)

这是组件更新之后触发的生命周期钩子,在这里可以拿到更新后的DOM

在componentDidUpdate中最好不要使用setState,因为可能会导致无限递归渲染

componentWillUnmount()

这是组件卸载之前的生命周期钩子,通常在该函数中销毁一些组件依赖的资源,比如计时器或者注册的全局事件

新版生命周期

总览

file

删除的API

  • componentWillMount
  • componentWillUpdate
  • componentWillReceiveProps

旧版的生命周期函数非常的对称,有componentWilUpdate对应componentDidUpdate,有componentWillMount对应componentDidMount;也考虑到了因为父组件引发渲染可能要根据props更新state的需要,所以有componentWillReceiveProps。

但是,这个生命周期函数的组合在Fiber之后就显得不合适了,如果开启async rendering,在render函数之前的所有函数,都有可能被执行多次。所以为了安全考虑,react废弃了这三个API

static getDerivedStateFromProps(props, state)

getDerivedStateFromProps是一个静态函数,所以函数体内不能访问this,简单说,就是一个纯函数

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

getDerivedStateFromProps是componentWillReceiveProps的替代品,但是前者比后者更安全,因为不能访问this,就可以避免开发者做很多预料之外的操作,因为这个hook的设计初衷是根据props更新state

getSnapshotBeforeUpdate()

这函数会在render之后执行,而执行之时DOM元素还没有被更新,开发者可以在这时获取dom的一些信息(比如保存网页滚动条位置)

函数的返回值会作为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);
}

参考

React生命周期

React v16.3之后的组件生命周期函数