来自 《深入 React 技术栈》,手打加深理解。

一、基本认识

对于 React 生命周期的认识,很多人都停留在几个方法以及他们的执行顺序,而实际上很多问题也没有搞清楚。

下面是基础的一些认识:

  • 首次挂载组件,会顺序执行 getDefaultPropsgetInitialStatecomponentWillMountrendercomponentDidMount
  • 卸载组件时,执行 componentWillUnmount
  • 重新挂载组件,顺序执行getInitialStatecomponentWillMountrendercomponentDidMount,但是并不会执行 getDefaultProps
  • 再次渲染组件时,组件将接受更新状态,此时顺序执行 componentWillReceivePropsshouldComponentUpdaterendercomponentDidUpdate

在通过 class 创建组件的时候,static defaultProps= {} 本质是调用内部的 getDefaultProps ,在 constructor 中设置 this.state = {} 本质是调用内部的 getInitialState 方法。

深入 React 技术栈给出的一张执行顺序图:

1.jpg

上图来自 《深入 React 技术栈》 图 3-9

二、MOUNTING 阶段

mountComponent 负责管理生命周期中的 getInitialStatecomponentWillMountrendercomponentDidMount

为什么 getDefaultProps 只执行一次?

在 First Render 中执行一次之后,getDefaultProps 不会在 Unmount / Second Render / Props Change / State Change 中再执行 (这和 getInitialState 明显不同,getInitialState 在 Second Render 中会再次执行)。

由于 getDefaultProps 是通过构造函数进行管理的,因此是在整个生命周期中最先开始执行的。而 mountComponent 无法调用到 getDefaultProps

mountComponent 主要的工作内容如下:

  • 初始化序号、标记等参数(组件挂在时,会分配一个递增序号,表示执行 ReactUpdates 时更新组件的顺序)
  • 判断是否是无状态组件,并初始化 props、context 等参数
  • 通过 getInitialState 获取初始化 state
  • 初始化更新队列和更新状态
  • 如果存在 componentWillMount 则执行
  • 触发渲染 render
  • 如果存在 componentDidMount 则执行

注意点1:在 componentWillMount 中执行 setState

componentWillMount 执行 setState 不会触发 re-render,只是把 state 进行合并,并且在 componentWillMountthis.state 不是最新的,在 render 中才能够获取更新之后的 this.state

React 是利用更新队列 this._pendingStateQueue 以及更新状态 this._pendingReplaceStatethis._pendingForceUpdate 来实现 setState 的异步更新机制。

注意点2:父子组件调用顺序

mountComponent 本质上是通过递归渲染内容,因此 父组件的 componentWillMount 在其子组件的 componentWillMount 之前调用,而父组件的 componentDidMount 在其子组件的 componentDidMount 之后调用。

示意图:

2.jpg

上图来自 《深入 React 技术栈》 3-11

三、RECEIVE_PROPS 阶段

updateComponent 负责管理生命周期中的 componentWillReceivePropsshoudComponentupdatecomponentWillUpdarerendercomponentDidUpdate

updateComponent的工作内容:(如果组件需要更新)

  • 如果存在 componentWillReceiveProps,则执行
  • 调用 shouldComponentUpdate 判断组件是否需要进行更新(如果返回 true,则进行下面操作)
  • 如果存在 componentWillUpdate 则执行
  • 进行渲染
  • 如果存在 componentDidUpdate ,则执行

注意点1: 在 componentWillReceiveProps 中调用 setState

componentWillReceiveProps 中调用 setState 不会触发 re-render,只是会合并 state 。并且在 componentWillReceivePropsshouldComponentUpdatecomponentWillUpdate 中都无法回去更新之后的 this.state,此时 this.state 仍然是未更新的 state。

只有在 rendercomponentDidUpdate 中才能获取更新后的 this.state

注意点2:父子组件调用顺序

updateComponent 也是通过递归渲染内容,因此父组件的 componentWillUpdate 是在子组件的 componentWillUpdate 之前调用,而父组件的 componentDidUpdate 是在子组件的 componentDidUpdate 之后调用。

注意点3:死循环

禁止在 shouldComponentUpdatecomponentWillUpdate 中调用 setState,这会造成循环调用,直至浏览器内存耗光后崩溃。

RECEIVE_PROPS 阶段示意图:

3.jpg

上图来自 《深入 React 技术栈》 图 3-12

三、UNMOUNTING 阶段

unmountComponent 负责管理生命周期中的 componentWillUnmount

unmountComponent 处理过程:

  • 如果存在 componentWillUnmount,则执行并重置所有相关参数、更新对垒以及更新状态

注意点1:在 componentWillUnmount 中调用 setState

componentWillUnmount 中调用 setState 是不会触发 re-render 的,因为此时所有的更新队列和更新状态都被重置为 null,并且清楚了公共类,完成了组件的卸载操作。