专栏首页黄腾霄的博客2020-5-30-理解React如何实现批量状态更新

2020-5-30-理解React如何实现批量状态更新

今天和大家聊一聊React如何实现批量状态更新。


引子

我们知道React的setState方法并不是同步执行的。

在React的生命周期中发生的多次setState的变更会进行合并,最终减少推送给浏览器的DOM变更次数,从而提升前端性能。

那么这部分到底是怎么实现的呢?我们来看下

Transaction

在React执行点击事件或者生命周期函数时,会使用一个Transaction对象将整个执行过程包裹成一个事务。

Transaction对象结构如下图所示

<pre>
 *                       wrappers (injected at creation time)
 *                                      +        +
 *                                      |        |
 *                    +-----------------|--------|--------------+
 *                    |                 v        |              |
 *                    |      +---------------+   |              |
 *                    |   +--|    wrapper1   |---|----+         |
 *                    |   |  +---------------+   v    |         |
 *                    |   |          +-------------+  |         |
 *                    |   |     +----|   wrapper2  |--------+   |
 *                    |   |     |    +-------------+  |     |   |
 *                    |   |     |                     |     |   |
 *                    |   v     v                     v     v   | wrapper
 *                    | +---+ +---+   +---------+   +---+ +---+ | invariants
 * perform(anyMethod) | |   | |   |   |         |   |   | |   | | maintained
 * +----------------->|-|---|-|---|-->|anyMethod|---|---|-|---|-|-------->
 *                    | |   | |   |   |         |   |   | |   | |
 *                    | |   | |   |   |         |   |   | |   | |
 *                    | |   | |   |   |         |   |   | |   | |
 *                    | +---+ +---+   +---------+   +---+ +---+ |
 *                    |  initialize                    close    |
 *                    +-----------------------------------------+
 * </pre>

在Transcation对象中整个执行效果有些类似我们平时做的单元测试。

分为初始化,执行和清理。

这样就可以在我们所有生命周期函数和点击事件中的setState方法调用前设置一个环境——isBatchingUpdates。

这个环境有什么作用呢?

实际上,所有的setState会将生成一个update对象,并加入到一个队列中。

接着会调用下面的requestWork方法,进行更新的任务调度。

而在其中,会判断isBatchingUpdates是否为true。

如果是,则将任务放置在队列,等待UnbatchingUpdates时统一执行

否则,就会同步执行。

最新源码

如果你现在去拉react的最新代码,会发现里面已经找不到Transcation这个类了。

不过你可以在ReactFiberWorkLoop文件中,找到batchedEventUpdates这个方法。

里面的实现基本是和transcation一样的,只是bool值换成了枚举

存在问题

可能聪明的小伙伴已经看出了这个地方存在的问题。

就是如果setState不在这个transcation过程中执行,那么就会导致同步更新。

也就是说如果要实现transcation的效果,必须setState在同步方法中调用。

比如说通过setTimeout方法,异步设置state。

此时setState在执行requestWork时,会发现已经处于Transcation之外了,isBatchingUpdates就会是false。

从而每次setState都会导致render,降低性能。

有兴趣的同学,可以在这个代码示例中,看到这里在普通事件和promise的回调中,setState导致的render次数不同。

解决方案

那有没有办法对这类的setState调用也进行批量执行呢?

有的。

第一种方式是,将所有的更新放到一个setState中。比如

setState({
	a:,
	b:
});

这样只会触发一次更新。

第二种方式是通过ReactDOM.unstable_batchedUpdates方法,这样

ReactDOM.unstable_batchedUpdates(() => {
        setState({a:});
		setState({b:});
      });

这里最终会调用到React的batchedUpdates方法,也是类似Transcation的方式,将执行包裹在一个BactedContext的环境中。从而实现批量调用。


参考文档:


本文会经常更新,请阅读原文: https://xinyuehtx.github.io/post/%E7%90%86%E8%A7%A3React%E5%A6%82%E4%BD%95%E5%AE%9E%E7%8E%B0%E6%89%B9%E9%87%8F%E7%8A%B6%E6%80%81%E6%9B%B4%E6%96%B0.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。

本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名黄腾霄(包含链接: https://xinyuehtx.github.io ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 2019-11-13-C++CLI的托管字符串std字符串和c字符串的转换

    在C++/CLI中,我们可以接触到三种字符串std::string,System::string,cstring。这里我们分别称之为标准字符串,托管字符串和c语...

    黄腾霄
  • WPF程序在shutdown期间引发的TaskCanceledException

    问题是这样的,从5月份开始,陆续有公司发现自己的WPF软件收到大量用户报告TaskCanceledException 异常,

    黄腾霄
  • 2020-5-10-RESTfulAPI中能否使用query string

    之前2020-5-6-restful理解 - huangtengxiao和大家介绍了对RESTful的理解。然后就有小伙伴问了我灵魂问题,对于RESTfulAP...

    黄腾霄
  • 走在专家的路上,每天优化一条SQL

    前段时间我们分享过一篇文章,巧用复合索引,有效降低系统IO,围绕B*Tree索引的使用,解读了如何合理地使用索引,尤其是复合索引,以及通过正确的索引类型来提高性...

    数据和云
  • 2018年swoole实战3-异步毫秒定时器服务端客户端启动服务

    项目中需要使用定时器时,crontab是常用的选择,不过crontab的粒度太大,最小时间单位是分钟级别,如果我们要设置秒级,甚至毫秒级的定时器,crontab...

    章鱼喵
  • 用Vue实现一个全选指令

    最近用vue做了两个项目,都需要实现全选反选的功能,两个项目用了两种实现方法,第一个项目用vue的computed,第二个项目用指令来实现,用起来,发觉指令更加...

    对角另一面
  • 架构|当你在浏览器访问www.taobao.com之后...

    黄小怪
  • spring注解之@Import注解的三种使用方式

    对应的import的bean都将加入到spring容器中,这些在容器中bean名称是该类的全类名 ,比如com.yc.类名

    HUC思梦
  • 一种改进的标准正态分布的精确采样算法(CS DS)

    2016年,Karney提出了一种用于标准正态分布的精确采样算法。在本文中,我们研究了随机偏差模型下该算法的计算复杂度。具体来说,Karne的算法要求访问范围为...

    WEIIILII
  • 区块链技术面试常被问到的Hyberledger Fabric关键概念

    先给英文官方原文地址:https://hyperledger-fabric.readthedocs.io/en/latest/overview.html

    圆方圆学院

扫码关注云+社区

领取腾讯云代金券