详解react setState
setstate是同步还是异步
自定义合成事件和react钩子函数中异步更新state
以在自定义click事件中的setstate为例
点击一次,最终this.state.count的打印结果是1,页面展示的是2。通过现象看,三次setstate只是最后一次setstate生效了,前两次都setstate无效果。因为假如把第一次setstate改为+3,count打印结果为1,展示结果为2,没有发生变化。而且没有同步获得count的结果。
此时,我们可以调整代码,通过setstate的第二个参数,来获得更新后的state:
此时,点击一次,三个setstate的回调函数中,打印结果分别是。
1
1: 2
2: 2
3: 2
首先,最后一行直接打印1。然后,在setstate的回调中,打印出的结果都是最新更新的2。虽然前两次setstate未生效,但是它们第二个参数中还是会打印出2。
此时将setstate的第一个参数换成函数,通过函数的第一个参数可以获得更新前的state。
此时,打印出的结果为1,但是页面展示出来的count为4。可以发现,如果setstate以传参的方式去更新state,几次setstate并不会只更新最后一次,而是几次更新state都会生效。
接下来看下第二个函数中打印的count是多少:
此时,点击一次,三个setstate的回调函数中,打印结果如下,可想而知,页面的展示结果也为4
1
1: 4
2: 4
3: 4
将上边代码放入如componentdidmount中,输出结果跟上边一致。
因为,可以得知,在自定义合成事件和钩子函数中,state的更新是异步的。
原生事件和settimeout中同步更新state
以在settimeout中setstate为例
此时,打印出的结果如下:
1: 2
2: 3
3: 4
4
将setstate第一个参数换为函数:
打印出的结果和上边一致。
是不是有一种state完全可控的感觉,在settimeout中,多次setstate都会生效,而且在每一个setstate的第二个参数中都可以得到更新后的state。
同样地,在原生事件中输出地结果和settimeout中一致,也是同步的。
setstate相关源码
如下代码均来自react17.0.2版本
目录 ./packages/react/src/reactbaseclasses.js
setstate可以接收两个参数,第一个参数可以是object,function,和null,undefined,就不会抛出错误。执行下边的this.updater.enqueuesetstate方法。全局查找enqueuesetstate,找到两组目录下有这个变量。
首先是第一组目录:
目录 ./packages/react/src/reactnoopupdatequeue.js 第100行enqueuesetstate方法,参数分别为this,初始化state,回调,和字符串setstate,this是指当前react实例。
接着看warnnoop方法:
这段代码相当于给didwarnstateupdateforunmountedcomponent对象中加入属性,属性的key为react 当前要setstate的组件.setstate,如果当前有这个属性则返回;如果当前没这个属性或者这个属性值为false,则设置这个属性的值为true。
再去看另外一个目录:
目录 ./react-reconciler/src/reactfiberclasscomponent.new.js和reactfiberclasscomponent.old.js
其中主要看 enqueueupdate 这个函数
目录 ./react-reconciler/src/reactupdatequeue.new.js和reactupdatequeue.old.js
看到这里,发现这个方法是将此次更新的update加入到更新队列中,而在这个版本中并没有发现isbatchingupdates这个属性的出现。貌似react fiber改动还挺大,暂时先写到这里,如果有新的发现会补充到这里。
总结
- 自定义合成事件和react钩子函数中异步更新state
- 原生事件和settimeout中同步更新state
以上就是详解react setstate的详细内容,更多关于react setstate的资料请关注其它相关文章!