Description
前言
现在写 React,通常是 hooks 用得比较多,但 class 组件还是有用到的地方。理解 React 组件的生命周期,有助于我们写出更好的 React 组件和代码。不同版本的生命周期钩子有所不同,主要以 React 16 为分界线,分为 React15 和 React16 之后。
React 15 里的生命周期
以 初始化挂载
,更新阶段
,卸载阶段
来划分。其中初始化挂载
的生命周期钩子有:
constructor
componentWillMount
render
componentDidMount
: 大多数时候,初始化请求页面数据都是在这个钩子里写逻辑
更新阶段
触发的生命周期钩子有:
componentWillReceiveProps
: 只要是父组件发生了更新,就会触发,即使父组件的 props 并没有变化shouldComponentUpdate
: 由组件自身的更新触发,如setState
。这个钩子常用来做性能优化,通过比较 props 来阻止后续生命周期的执行componentWillUpdate
render
componentDidUpdate
: 常用来执行一些更新操作,比如 DOM 修改,通知父组件数据变化等等
卸载阶段
只有一个钩子:
componentWillUnmount
以上就是 React15 版本下的生命周期函数
React 16 的生命周期改动
从 React16 开始,生命周期钩子进行了比较大的调整,主要是去掉了一些比较鸡肋的生命周期如 componentWillMount
,componentWillUpdate
等,另外还有几个新的生命周期钩子加入。这个 开源项目 展示了 React16.3 版本的生命周期图:
可以看到,在初始化挂载
阶段,主要有以下几个生命周期:
constructor
static getDerivedStateFromProps
: 需要返回一个对象,对象里是组件的 state 的数据,React 会差量更新 state 而不是直接覆盖更新render
componentDidMount
相比 React15,React16 去掉了 componentWillMount
,新增了 getDerivedStateFromProps
钩子,这个钩子的目的主要是为了取代 componentWillReceiveProps
,它的基本理念是 实现 props 到 state 的映射
,只做这件事,为了限制其使用场景,React 把这个钩子设置成了静态方法
,这意味着 this
是获取不到的,可以减少用户的一些错误使用。另外,在 React16.3 中,只有父组件的更新
才会触发这个钩子,而 React16.4 之后,任何因素
的更新都会触发这个钩子执行。下图是 React16.4 之后的生命周期图,可以和上面那张图对比下:
在更新阶段
,主要有以下几个钩子:
static getDerivedStateFromProps
shouldComponentUpdate
render
getSnapshotBeforeUpdate
componentDidUpdate
相比 React15,更新阶段新增了 getDerivedStateFromProps
,getSnapshotBeforeUpdate
,移除了 componentWillUpdate
。
在 卸载阶段
,与 React15 一样,只有一个钩子:
componentWillUnmount
Fiber 架构
为什么 React16 要大改生命周期呢?原因就是新的 Fiber
架构。
React 每一次更新组件,都会先拿到用户在 render
方法里的写的 JSX,然后编译生成虚拟 DOM,再使用 diff
算法与上一次的虚拟 DOM 内容做比较,然后定向更新 DOM 。在 React16 之前,这个更新是一个 同步递归
的过程,这意味着一旦进入更新,主线程就会被占住不放,浏览器就无法响应用户的其它交互操作,一直等到递归更新完成。这在 用户体验层面
带来了巨大的风险,可能会造成浏览器假死无法响应的状态。为了解决这个问题,React 团队在 React16 引入了新的 Fiber
架构,Fiber 架构做的事情就是 把原本同步渲染的过程变成可打断的异步更新
。
具体来说,Fiber 会把原本的同步更新任务,拆分成一个个小任务,并且还有任务优先级调度的概念,这意味着每次更新的时候,一个小任务执行完,是可以把主线程交还出去执行其他任务的。通过把大任务拆分成小任务,这样在渲染更新的时候是可以打断再重新恢复的,那这就意味着有些生命周期可能会被反复执行,所以一些可能导致出问题的生命周期函数就必须废弃掉或换成更合适的来保证渲染过程的安全。因此,componentWillMount
这个生命周期被废弃掉了,componentWillReceiveProps
这个生命周期废弃了,取而代之的是 getDerivedStateFromProps
;componentWillUpdate
也废弃了,换成新的 getSnapshotBeforeUpdate
。
总结
一个好的框架应该是提供一些简洁易用的 API,引导用户在正确的环境下做正确的事。React16 通过改造生命周期,引入新的 Fiber
架构带给 React 开发者更好的使用体验。