浅入深出setState(上篇)

Part one - setState点燃引擎

setState点燃引擎

这是一个React组件实现组件可交互所需的流程,render()输出虚拟DOM,虚拟DOM转为DOM,再在DOM上注册事件,事件触发setState()修改数据,在每次调用setState方法时,React会自动执行render方法来更新虚拟DOM,如果组件已经被渲染,那么还会更新到DOM中去。
这个过程,setState就像一个点燃引擎的打火石,发动了React核心的调度层,然后直至渲染层的改变。

Part two - setState是异步的

刚接触React的同学,对React的setState的使用偶尔会有一些偏颇,出现一些意料之外的情况。
比如:

onClickForReset=()=>{
    this.setState({value: []});
    // 此刻立马取this.state做一些同步操作
    console.log(this.state.value);
}

或者是

increateCount(){
    this.setState({count: this.state.count + 1});
    this.setState({count: this.state.count + 1});
    this.setState({count: this.state.count + 1});
}

我们可以看一个现在的例子:
https://codesandbox.io/s/qqy9n5o2m9

https://codesandbox.io/s/qqy9n5o2m9

setState比较熟练的同学可以跳过这一段代码,但是有些刚学会使用React的同学经常会犯这个错误,一开始我只能粗暴地说:

  1. setState是异步的,不会立即改变state的值。
  2. 多次setState调用生成的效果会合并。
  3. 第二个参数可以是一个回调函数。
  4. setState可以接受一个函数(例子改动)

后来我逐渐也在想下面这两个问题,现在这篇文章试图尽量弄清的两件事:

  1. 为什么要把setState设计成异步的,缘由是什么,解决了什么问题,有什么好处?
  2. 如何实现异步的setState,整体原理是怎样的,有没有什么特殊的骚操作?

我们可以自己也想一想,下面留给大家一片空白区。😝

<div style="background:#fff;width:100%;height:500px;margin-bottom:30px;"></div>

好,我们带着这两个问题和自己的猜想,试图一探究竟。

Part three - 为什么要异步

简单的来说:在批量多次的更新中,延缓到最后合并渲染是有好处的。

万剑归宗

  1. 保证内部的一致性:首先,我想我们都同意推迟并批量处理重渲染是有益而且对性能优化很重要的,无论 setState() 是同步的还是异步的。那么就算让 state 同步更新,props 也不行,因为当父组件重渲染(re-render )了你才知道 props。
  2. 在批量多次的更新中,延缓到最后合并渲染是有好处的。这一点,和我们熟知的防抖动函数的出发点类似,我们普遍认为在许多情况下在同一时间段,频繁setState触发渲染,连续同步效率很低,对性能有极大损耗。

我们来看下setState引发组件的更新过程就知道了:

setState引发组件的更新过程

每一次setState如果都引发一次组件更新,走完一圈生命周期,实在是有点粗糙和浪费,生命周期函数为纯函数性能应当还能够接受,可是render函数内返回的虚拟DOM去做比较这个就比较费时间了。

直观的感受是,React将多个setState产生的修改放在一个队列里,缓一缓,攒在一起,等待时机,觉得差不多了再引发一次更新过程。这样,在每次更新过程中,会把积攒的setState结果合并,做一个merge的动作,节省render触发的频率。
这样,对于开发者而言,可以在同步代码中随意多行调用setState函数而不用担心重复setState重复render的问题。

然后,总是被大家误用不理解的也是这一点,所以后来,setState方法的第二个参数慢慢被进入大家的视野了,作为回调函数可以再次拿到新的this.state值。

再后来,一个setState函数的隐藏功能进入了大家的视野,那就是,setState可以接受一个函数作为参数。

更多:https://github.com/facebook/react/issues/11527#issuecomment-360199710

Part four - 怎么实现异步

在此之前,我们来看一个例子…可能会颠覆你对setState的认识

我们可以直接打开在线案例:https://codesandbox.io/s/vq1nqkvyw5

setState真的是异步吗

提问:实际运行结果是怎么样的?好吧现在下

Part five - 彩蛋:setState真的是异步吗?

我们上面一个例子告诉我们:

No! 可能是同步 超出React生命周期和React代理事件之外都是同步

预知后事如何,请看下半篇。


1.2k 声望
41 粉丝
0 条评论
推荐阅读
美业微前端的落地
2020年4月,有赞美业的前端团队历经7个月时间,完成了美业PC架构从单体SPA到微前端架构的设计、迁移工作。PPT在去年6月份就有了,现在再整理一下形成文章分享给大家。

边城到此莫若34阅读 5.8k评论 10

安全地在前后端之间传输数据 - 「3」真的安全吗?
在「2」注册和登录示例中,我们通过非对称加密算法实现了浏览器和 Web 服务器之间的安全传输。看起来一切都很美好,但是危险就在哪里,有些人发现了,有些人嗅到了,更多人却浑然不知。就像是给门上了把好锁,还...

边城31阅读 7.2k评论 5

封面图
涨姿势了,有意思的气泡 Loading 效果
今日,群友提问,如何实现这么一个 Loading 效果:这个确实有点意思,但是这是 CSS 能够完成的?没错,这个效果中的核心气泡效果,其实借助 CSS 中的滤镜,能够比较轻松的实现,就是所需的元素可能多点。参考我们...

chokcoco20阅读 2.1k评论 2

在前端使用 JS 进行分类汇总
最近遇到一些同学在问 JS 中进行数据统计的问题。虽然数据统计一般会在数据库中进行,但是后端遇到需要使用程序来进行统计的情况也非常多。.NET 就为了对内存数据和数据库数据进行统一地数据处理,发明了 LINQ (L...

边城17阅读 1.9k

封面图
【已结束】SegmentFault 思否写作挑战赛!
SegmentFault 思否写作挑战赛 是思否社区新上线的系列社区活动在 2 月 8 日 正式面向社区所有用户开启;挑战赛中包含多个可供作者选择的热门技术方向,根据挑战难度分为多个等级,快来参与挑战,向更好的自己前进!

SegmentFault思否20阅读 5.6k评论 10

封面图
过滤/筛选树节点
又是树,是我跟树杠上了吗?—— 不,是树的问题太多了!🔗 相关文章推荐:使用递归遍历并转换树形数据(以 TypeScript 为例)从列表生成树 (JavaScript/TypeScript) 过滤和筛选是一个意思,都是 filter。对于列表来...

边城18阅读 7.7k评论 3

封面图
Vue2 导出excel
2020-07-15更新 excel导出安装 {代码...} src文件夹下新建一个libs文件夹,新建一个excel.js {代码...} vue页面中使用 {代码...} ===========================以下为早期的文章今天在开发的过程中需要做一个Vue的...

原谅我一生不羁放歌搞文艺14阅读 20k评论 9

1.2k 声望
41 粉丝
宣传栏