react 16.3生命周期更新解析
React v16.3虽然是一个小版本升级,但是却对React组件生命周期函数有巨大变化。
文章梗概
- 新版本+2-3个生命周期。
- 为什么增加那2个生命周期?
- 为什么减去之前3个生命周期?
- 相关知识延伸
正文
React v16.0刚推出的时候,是增加了一个componentDidCatch生命周期函数(看文末错误边界),这只是一个增量式修改,完全不影响原有生命周期函数;但是,到了React v16.3,大改动来了,引入了两个新的生命周期函数:
- getDerivedStateFromProps
- getSnapshotBeforeUpdate
先来看React v16.3之前的生命周期函数(图中实际上少了componentDidCatch),如下图。


这个生命周期函数非常的对称,有componentWilUpdate对应componentDidUpdate,有componentWillMount对应componentDidMount;也考虑到了因为父组件引发渲染可能要根据props更新state的需要,所以有componentWillReceiveProps。
但是,这个生命周期函数的组合在Fiber(React Fiber是什么,看文末解释)之后就显得不合适了,因为,如果要开启async rendering,在render函数之前的所有函数,都有可能被执行多次。长期以来,原有的生命周期函数总是会诱惑开发者在render之前的生命周期函数做一些动作,现在这些动作还放在这些函数中的话,有可能会被调用多次,这肯定不是你想要的结果。
为什么不在componentWillMount里写AJAX获取数据的功能,他们的观点是,componentWillMount在render之前执行,早一点执行早得到结果。要知道,在componentWillMount里发起AJAX,不管多快得到结果也赶不上首次render,而且componentWillMount在服务器端渲染也会被调用到(当然,也许这是预期的结果),这样的IO操作放在componentDidMount里更合适。在Fiber启用async render之后,更没有理由在componentWillMount里做AJAX,因为componentWillMount可能会被调用多次,谁也不会希望无谓地多次调用AJAX吧。 道理说了都明白,但是历史经验告诉我们,不管多么地苦口婆心教导开发者不要做什么不要做什么,都不如直接让他们干脆没办法做。
随着getDerivedStateFromProps的推出,同时deprecate了一组生命周期API,包括:
- componentWillReceiveProps
- componentWillMount
- componentWillUpdate
可以看到,除了shouldComponentUpdate之外,render之前的所有生命周期函数全灭,就因为太多错用滥用这些生命周期函数的做法,预期追求对称的美学,不如来点实际的,让程序员断了在这些生命周期函数里做些不该做事情的念想。
至于shouldComponentUpdate,如果谁还想着在里面做AJAX操作,那真的是没救了。
按照官方说法,以前需要利用被deprecate的所有生命周期函数才能实现的功能,都可以通过getDerivedStateFromProps的帮助来实现。
这个getDerivedStateFromProps是一个静态函数,所以函数体内不能访问this,简单说,就是应该一个纯函数,纯函数是一个好东西啊,输出完全由输入决定。
static getDerivedStateFromProps(nextProps, prevState) {
//根据nextProps和prevState计算出预期的状态改变,返回结果会被送给setState
}
看到这样的函数声明,应该感受到React的潜台词:老实做一个运算就行,别在这里搞什么别的动作。
每当父组件引发当前组件的渲染过程时,getDerivedStateFromProps会被调用,这样我们有一个机会可以根据新的props和之前的state来调整新的state,如果放在三个被deprecate生命周期函数中实现比较纯,没有副作用的话,基本上搬到getDerivedStateFromProps里就行了;如果不幸做了类似AJAX之类的操作,首先要反省为什么自己当初这么做,然后搬到componentDidMount或者componentDidUpdate里面去。
所有被deprecate的生命周期函数,目前还凑合着用,但是只要用了,开发模式下会有红色警告,在下一个大版本(也就是React v17)更新时会彻底废弃。
React v16.3还引入了一个新的声明周期函数getSnapshotBeforeUpdate,这函数会在render之后执行,而执行之时DOM元素还没有被更新,给了一个机会去获取DOM信息,计算得到一个snapshot,这个snapshot会作为componentDidUpdate的第三个参数传入。
getSnapshotBeforeUpdate(prevProps, prevState) {
console.log('#enter getSnapshotBeforeUpdate');
return 'foo';
}
componentDidUpdate(prevProps, prevState, snapshot) {
console.log('#enter componentDidUpdate snapshot = ', snapshot);
}
上面这段代码可以看出来这个snapshot怎么个用法,snapshot咋看还以为是组件级别的某个“快照”,其实可以是任何值,到底怎么用完全看开发者自己,getSnapshotBeforeUpdate把snapshot返回,然后DOM改变,然后snapshot传递给componentDidUpdate。
官方给了一个例子,用getSnapshotBeforeUpdate来处理scroll,坦白说,我也想不出其他更常用更好懂的需要getSnapshotBeforeUpdate的例子,这个函数应该大部分开发者都用不上(听得懂我的潜台词吗:不要用!)
所以,React v16.3之后的生命周期函数一览图成了这样。


可以注意到,说getDerivedStateFromProps取代componentWillReceiveProps是不准确的,因为componentWillReceiveProps只在Updating过程中才被调用,而且只在因为父组件引发的Updating过程中才被调用);而getDerivedStateFromProps在Updating和Mounting过程中都会被调用。
此外,从上面这个也看得出来,同样是Updating过程,如果是因为自身setState引发或者forceUpdate引发,而不是不由父组件引发,那么getDerivedStateFromProps也不会被调用。
这其实容易引发一些问题,不用仔细想,光是由此让开发者不得不理解这乱七八糟的差异,就可以知道这是一个大坑! 还好,React很快意识到这个问题,在React v16.4中改正了这一点,改正的结果,就是让getDerivedStateFromProps无论是Mounting还是Updating,也无论是因为什么引起的Updating,全部都会被调用。
这样简单多了!
总结
用一个静态函数getDerivedStateFromProps来取代被deprecate的几个生命周期函数,就是强制开发者在render之前只做无副作用的操作,而且能做的操作局限在根据props和state决定新的state,而已。
这是进一步施加约束,防止开发者乱来,我说过,施加约束的哲学指导思想,是我最爱React的原因。
延伸
生命周期定义错误边界
https://zh-hans.reactjs.org/docs/error-boundaries.html 如果一个 class 组件中定义了 static getDerivedStateFromError() 或 componentDidCatch() 这两个生命周期方法中的任意一个(或两个)时,那么它就变成一个错误边界。当抛出错误后,请使用 static getDerivedStateFromError() 渲染备用 UI ,使用 componentDidCatch() 打印错误信息。
React Fiber是个什么东西呢?
官方的一句话解释是“React Fiber是对核心算法的一次重新实现”。这么说似乎太虚无缥缈,所以还是要详细说一下。
不用太紧张,不要以为React Fiber的到来是一场大革命,实际上,对我们只是把React当做工具的开发者来说,很可能感觉不到有什么功能变化。等到React v16发布的时候,我们修改package.json中的react版本号,重新npm install,一切就搞定了,然后我们就感觉到网页性能更高了一些,如此而已。
之前react更新一个组件,主线程专心运行,浏览器主线程被React占着呢,抽不出空,最后的结果就是用户敲了按键看不到反应,等React更新过程结束之后,咔咔咔那些按键一下子出现在input元素里了。很不好的体验。
更新以后,破解JavaScript中同步操作时间过长的方法其实很简单——分片。它把一个耗时长的任务分成很多小片,每一个小片的运行时间很短,虽然总时间依然很长,但是在每个小片执行完之后,都给其他任务一个执行的机会,这样唯一的线程就不会被独占,其他任务依然有运行的机会。
维护每一个分片的数据结构,就是Fiber。
react官网生命周期说明: https://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/
react 16.3生命周期更新解析的更多相关文章
- React 16.4 生命周期
补一下 React 16.4版本的生命周期图
- react学习小结(生命周期- 实例化时期 - 存在期- 销毁时期)
react学习小结 本文是我学习react的阶段性小结,如果看官你是react资深玩家,那么还请就此打住移步他处,如果你想给一些建议和指导,那么还请轻拍~ 目前团队内对react的使用非常普遍,之 ...
- React组件和生命周期简介
React 简介----React 是 Facebook 出品的一套颠覆式的前端开发类库.为什么说它是颠覆式的呢? 内存维护虚拟 DOM 对于传统的 DOM 维护,我们的步骤可能是:1.初始化 ...
- 2. React组件的生命周期
2. React组件的生命周期 使用React开发时候用到最多的就是React的组件了,通过继承React.Component,加入constructor构造函数,实现Render方法即可.这当中Re ...
- Vue与React的异同 -生命周期
vue的生命周期 创建前 beforeCreate 创建 create 挂载前 beforeMount 挂载 mounted 更新前 beforeUpdate 更新 updated 销毁前 bef ...
- React 组件的生命周期方法
React 组件的生命周期方法 按渲染顺序: 1: componentWillMount() – 在渲染之前执行,在客户端和服务器端都会执行. 2: componentDidMount() – 仅在第 ...
- React 之 组件生命周期
React 之 组件生命周期 理解1) 组件对象从创建到死亡它会经历特定的生命周期阶段2) React组件对象包含一系列的勾子函数(生命周期回调函数), 在生命周期特定时刻回调3) 我们在定义组件时, ...
- 16、生命周期-BeanPostProcessor原理
16.生命周期-BeanPostProcessor原理 16.1 打断点运行postProcessBeforeInitialization 可以看到先执行的顺序为: applyBeanPostProc ...
- react第三单元(react组件的生命周期)
第三单元(react组件的生命周期) #课程目标 灵活掌握react组件的生命周期以及组件的活动过程. 能够灵活使用react的生命周期 #知识点 react的类组件的生命周期分为三个阶段 实例期 存 ...
- react js 之生命周期
react redux 结合是目前比较流行的前端开发框架,主要基于react 中的state 树为数据模型,借助redux 来控制 state 数据:下面直接从代码层面解析该框架中一个react 组件 ...
随机推荐
- 在不修改代码情况下解决 Chrome 浏览器跨域
前言: 在前后台分离的项目,跨域是经常遇到的问题了.是实际解决方案中,大部分采用服务端配置,而如果只是调试,可以通过配置 Chrome 浏览器实现跨域,以下以 NodeJs 服务为例. 开始: 1. ...
- k8s实战案例之运行WordPress
1.WordPress架构 LNMP案例之基于Nginx+PHP实现WordPress博客站点,要求Nginx+PHP运⾏在同⼀个Pod的不同容器;nginx主要作用是接入站点请求,如果请求静态资源n ...
- SpringBoot3.x原生镜像-Native Image实践
前提 之前曾经写过一篇<SpringBoot3.x 原生镜像-Native Image 尝鲜>,当时SpringBoot处于3.0.0-M5版本,功能尚未稳定.这次会基于SpringBoo ...
- OpenSSH版本升级漏洞修复问题
Hi, I'm @Merbelue 大家好,这篇为大家介绍二进制方式对OpenSSH版本升级,在生产环境中可用于解决版本升级.漏洞修复等. @ 目录 1.环境 2.安装telnet 2.1.检查是否安 ...
- RocketMQ系列(一) 基本介绍
RocketMQ系列(一) 基本介绍 1.MQ 作用 MQ 的应用场景主要包含以下 3 个方面: 1.1.异步与解耦 当我们下了一个订单之后,订单服务会进行 RPC 同步调用 支付服务.库存服务.物流 ...
- 使用 Sealos 在离线环境中光速安装 K8s 集群
作者:尹珉.Sealos 开源社区 Ambassador,云原生爱好者. 当容器化交付遇上离线环境 在当今快节奏的软件交付环境中,容器化交付已经成为许多企业选择的首选技术手段.在可以访问公网的环境下, ...
- 当你使用Taro时,你需要了解的一些事儿
2017 年 1 月 9 日凌晨,万众期待的微信小程序正式上线,前有跳一跳等爆圈小游戏的带动,后有特殊时期下各类健康码小程序的加持,小程序成为了国内技术圈独树一帜的存在.但随着小程序的迅猛发展,其实在 ...
- java类序列化和反序列化
参考:https://zhuanlan.zhihu.com/p/144535172?utm_id=0 https://blog.csdn.net/qq_42617455/article/details ...
- 「repost - from Quack」Matroid.md
拟阵?type=header 拟阵的定义与常见性质 & 拟阵交算法 拟阵的定义与常见性质 独立集系统和拟阵 定义独立集系统\(S=(E,\mathcal{I})\),\(E\)是基本元素的集合 ...
- 多租户基于Springboot+MybatisPlus实现使用一个数据库一个表 使用字段进行数据隔离
多租户实现方式 多租户在数据存储上主要存在三种方案,分别是: 1. 独立数据库 即一个租户一个数据库,这种方案的用户数据隔离级别最高,安全性最好,但成本较高. 优点:为不同的租户提供独立的数据库,有助 ...