react高级篇之setState是同步的还是异步的

1,127 阅读3分钟

本人已参与「新人创作礼」活动,一起开启掘金创作之路。

setState是同步的还是异步的?

在 react 18 版本以前


在同步环境中异步,在异步环境中同步。

setState本身并不具备绝对的同步/异步概念。 比如:在promise的then()方法中、setTimeOut()、setInterVal(),ajax的回调等异步环境中,setState就是同步的。同步环境下就是异步的。

react会有一个上下文环境,在同步环境中,setState处于react的上下文中,react会监控动作合并,所以这个时候setState()是异步的。

而在异步环境中,比如promise的then()方法中、setTimeOut()、setInterVal()中,react实际上已经脱离了react的上下文环境。所以setState()是同步执行的。

代码如下(示例):setState()的同步和异步的案例

const [state,setState] = useState(0);  //初始化为 0
//当前处于同步环境,所以setState是异步的
setState(1); 
console.log(state); //此时因为setState是异步的,state还未被赋值 打印结果是 0

setTimeOut(() => {
	//当前处于异步环境,所以setState()是同步的
	setState(5);
	console.log(state); //打印结果是5
},0)

setState()在react中一开始之所以被设定为异步触发,是因为每当触发setState时react需要去更新视图。

通过异步更新视图来合并在短时间内的大量setState动作。 举个例子:如果一短时间内setState()调用了100次,视图是否需要相对应的渲染100?所以为了防止这种情况,setState设置成异步,合并短时间内的多次改动,并集中统一渲染。

这样,当我们在短时间内多次的调用setState时,视图只会被更新一次。

代码如下(示例):setState()同步环境中异步执行 --合并动作案例

const [state,setState] = useState(0);

//快速给state赋值,连续赋值五次
for(let i =0;i<5;++i){
	setState(i);
}
//实际上,因为setState动作合并的特性,视图只会被更新一次而不是五次

以上案例中,虽然setState被赋值了五次,但,视图不会更新五次。因为动作合并的原因,视图只会更新一次,也就等于只执行了setState(4); 但是!! 这是setState在同步环境中触发异步更新机制的时候。 如果是在异步环境中呢? 我们看看案例。

代码如下(示例):setState()异步环境中同步执行 --不合并请求案例

const [state,setState] = useState(0);

//异步环境中快速给state赋值,连续赋值五次
Promise.resolve().then(() => {
	//当前处于异步环境。setStat同步进行
	for(let i =0;i<5;++i){
		setState(i);
	}
})

//在这次案例中,上面setState货真价实的被赋值了5次。视图也真真切切的被更新了五次

上面案例中,setState所处与异步环境中,所以同步执行,也就是不再进行等待直接修改state的值不进行请求合并,而state的值一旦被修改。react的视图就会更新。所以上面案例中,视图会被更新五次。

在 react 18 版本以后


setState()不论在同步环境还是异步环境都是异步的。

总结

  • react 18 版本之前,setState在同步环境中异步执行,异步环境中同步执行。
  • react 18 版本之后,不论在同步环境还是在异步环境中,setState都是异步的。
  • setState之所以会设置成异步是为了合并短时间内的多次渲染。
欢迎技术沟通,摸鱼聊天~

备注来自掘金~

wx:XXF1096032096