本人已参与「新人创作礼」活动,一起开启掘金创作之路。
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