为什么react的setState是异步的?
前言
大概几个月之前我有幸带几个小伙伴做了几个项目, 一直以来我都知道react
的setState
是异步的, 以及如何正确的使用setState
, 直到刚才提到的带着几个小伙伴做项目, 其中一个问我说他用setState
修改了一个state
, 但使用这个state
的时候依旧是之前的值, 然后我才发现setState
是一个异步的方法这个特性我忘记跟他们说了, 可能是由于我对这个太习以为常了吧, 觉得这个特性对我来说太自然了, 而这也是我打算写这篇文章的初衷
场景
那个使用了setState
之后state
依旧是旧值的场景大概如下:
import React, { PureComponent } from 'react';
class Demo extends PureComponent {
state = {
count: 0
}
click = () => {
const { count } = this.state;
this.setState({
count: count + 1
});
console.log(this.state.count);
}
render() {
const { count } = this.state;
return (
<div>
<button onClick={this.click}>+1</button>
<div>{count}</div>
</div>
);
}
}
export default Demo;
由于setState
是异步的, 那么此时我们调用setState
, 并且输出state
, 那么得到的永远会是修改之前的state
而解决方法有以下大致两种
方法一: 回调函数
我们把上面的setState
的代码修改为这样:
this.setState(
{
count: count + 1
},
() => {
console.log(this.state.count);
}
);
这个时候我们输出的state
就是修改之后的值了
方法二: componentDidUpdate
还有一个方法就是使用componentDidUpdate
这个生命周期方法, 这个生命周期方法会在组件挂载到DOM
树上之后, 组件重新渲染之后执行, 使用这个生命周期方法的话, 那么代码大致如下:
import React, { PureComponent } from 'react';
class Demo extends PureComponent {
state = {
count: 0
}
componentDidUpdate() {
const { count } = this.state;
console.log(count);
}
click = () => {
const { count } = this.state;
this.setState({
count: count + 1
});
}
render() {
const { count } = this.state;
return (
<div>
<button onClick={this.click}>+1</button>
<div>{count}</div>
</div>
);
}
}
export default Demo;
为他解决了这个问题之后我就开始思考这个问题了: 为何setState
是异步的呢?
为何setState是异步的
私以为是基于性能和体验的考虑, 试想一下如果我们需要更新多个state
:
import React, { PureComponent } from 'react';
import Comp1 from '@/components/Comp1';
import Comp2 from '@/components/Comp2';
import Comp3 from '@/components/Comp3';
class Demo extends PureComponent {
state = {
_1: 1,
_2: 2,
_3: 3
}
set1 = () => {
const { _1 } = this.state;
this.setState({
_1: _1 + 1
});
}
set2 = () => {
const { _2 } = this.state;
this.setState({
_2: _2 + 1
});
}
set3 = () => {
const { _3 } = this.state;
this.setState({
_3: _3 + 1
});
}
render() {
return (
<div>
<Comp1 click={this.set1} />
<Comp2 click={this.set2} />
<Comp3 click={this.set3} />
</div>
);
}
}
export default Demo;
此时需要调用setState
, 如果是同步的, 那么程序就会发生阻塞, 而react
的处理方法是将多个更新聚集(flush
)到一起, 然后执行一个批处理(batch
), 这样就能避免阻塞的发生
假设此时用户在做一些交互操作, 比如输入的操作, 那么异步的操作不会导致用户的收入行为被阻塞, 而是把更新渲染往后延, 这样体验会更好
同时还有一点, 当然这个是我个人的一个体会, 源于最近刚完成的一个大数据可视化的项目, 是展现一个数据处理流程的可视化大屏的项目, 这样的项目免不了动画和数据计算处理, 由于就一个页面, 不存在路由的切换, 同时数据都是假数据, 因此并未使用redux
, 而是直接使用了state
, 同时又有很多的用户交互, 而程序要响应用户的交互, 并据此来更新界面, 那么自然就会有很多setState
的动作了, 而此时如果setState
是同步的, 那么当计算和动画流程运行起来, 用户和程序产生交互程序更新界面的时候, 更新的动作就会使得程序阻塞, 此时动画和数字的计算就会停止, 那就麻烦了
当然了, 这只是个人的一点愚见, 同时也欢迎大家在评论区和我探讨, 同时附上官方文档中关于这个问题的解释和github
中关于这个问题的探讨
参考文献
转载自:https://juejin.cn/post/7076751722810933285