当我们在讨论 React 组件生命周期的时候,一定是在讨论类组件(Class Component)。函数式组件并没有生命周期的概念,因为它本身就是一个函数,只会从头执行到尾。

生命周期是一个抽象的概念,能让开发者产生联想记忆的往往是那些函数,比如 componentDidMount、componentWilMount 等等。然而这些函数并不是它的生命周期,只是在生命周期中按顺序被调用的函数。挂载 -> 更新 -> 卸载这一 React 组件完整的流程,才是生命周期。

挂载阶段

挂载阶段是指组件从初始化到完成加载的过程。

constructor

constructor 是类通用的构造函数,常用于初始化

getDerivedStateFromProps

本函数的作用是使组件在 props 变化时更新 state,

componentWillMount(待废弃)

用于组件即将加载前做某些操作,但目前被标记为弃用。因为在 React 的异步渲染机制下,该方法可能会被多次调用。

一个常见的错误是 componentWillMount 跟服务器端同构渲染的时候,如果在该函数里面发起网络请求,拉取数据,那么会在服务器端与客户端分别执行一次。所以更推荐在componentDidMount中完成数据拉取操作。

render

render 函数返回的 JSX 结构,用于描述具体的渲染内容。但切记,render 函数并没有真正的去渲染组件,渲染是依靠 React 操作 JSX 描述结构来完成的。还有一点需要注意,render 函数应该是一个纯函数,不应该在里面产生副作用,比如调用 setState 或者绑定事件。

那为什么不能 setState 呢?因为 render 函数在每次渲染时都会被调用,而 setState 会触发渲染,就会造成死循环。

那又为什么不能绑定事件呢?因为容易被频繁调用注册。

componentDidMount

主要用于组件加载完成时做某些操作,比如发起网络请求或者绑定事件,该函数是接着 render 之后调用的。但 componentDidMount 一定是在真实 DOM 绘制完成之后调用吗?在浏览器端,我们可以这么认为。

但在其他场景下,尤其是 React Native 场景下,componentDidMount 并不意味着真实的界面已绘制完毕。由于机器的性能所限,视图可能还在绘制中。

更新阶段

componentWillReceiveProps

getDerivedStateFromProps

本函数的作用是使组件在 props 变化时更新 state,

shouldComponentUpdate

该方法通过返回 true 或者 false 来确定是否需要触发新的渲染。因为渲染触发最后一道关卡,所以也是性能优化的必争之地。通过添加判断条件来阻止不必要的渲染。

React 官方提供了一个通用的优化方案,也就是 PureComponent。PureComponent 的核心原理就是默认实现了shouldComponentUpdate函数,在这个函数中对 props 和 state 进行浅比较,用来判断是否触发更新。

componentWillUpdate(待废弃)

同样已废弃,因为后续的 React 异步渲染设计中,可能会出现组件暂停更新渲染的情况

render

同挂载阶段一致

getSnapshotBeforeUpdate

getSnapshotBeforeUpdate 方法是配合 React 新的异步渲染的机制,在 DOM 更新发生前被调用,返回值将作为 componentDidUpdate 的第三个参数

componentDidUpdate

卸载阶段

卸载阶段就容易很多了,只有一个回调函数。

componentWillUnmount

该函数主要用于执行清理工作。一个比较常见的 Bug 就是忘记在 componentWillUnmount 中取消定时器,导致定时操作依然在组件销毁后不停地执行。所以一定要在该阶段解除事件绑定,取消定时器。