# 8.setState:是异步还是同步
详见: seState 是异步还是同步 (opens new window) useState 和 setState (opens new window)
# 结论:
- 在正常的 react 的事件流里(如 onClick 等)
- setState 和 useState 是异步执行的(不会立即更新 state 的结果)
- 多次执行 setState 和 useState,只会调用一次重新渲染 render
- 不同的是,setState 会进行 state 的合并,而 useState 则不会
- 在 setTimeout,Promise.then 等异步事件中
- setState 和 useState 是同步执行的(立即更新 state 的结果)
- 多次执行 setState 和 useState,每一次的执行 setState 和 useState,都会调用一次 render
原因是:react 会整合多个状态合并更新,减少 re-render 调用
只要你进入了 react 的调度流程,那就是异步的。只要你没有进入 react 的调度流程,那就是同步的。什么东西不会进入 react 的调度流程? setTimeout setInterval ,直接在 DOM 上绑定原生事件等。这些都不会走 React 的调度流程,你在这种情况下调用 setState ,那这次 setState 就是同步的。 否则就是异步的。
this.setState 和 useState 有所不同
- 同步执行时 useState 也会对 state 进行逐个处理,而 setState 则只会处理最后一次 如
class Component extends React.Component {
constructor(props) {
super(props)
this.state = {
a: 1,
}
}
handleClickWithPromise = () => {
Promise.resolve().then(() => {
this.setState({a: this.state.a + 1})
this.setState({a: this.state.a + 1})
})
}
handleClickWithoutPromise = () => {
this.setState({a: this.state.a + 1})
this.setState({a: this.state.a + 1})
}
render() {
console.log('a', this.state.a)
return (
<Fragment>
<button onClick={this.handleClickWithPromise}>异步执行</button>
<button onClick={this.handleClickWithoutPromise}>同步执行</button>
</Fragment>
)
}
}
//当点击同步执行按钮时,两次 setState 合并,只执行了最后一次,打印 2
// 当点击异步执行按钮时,两次 setState 各自 render 一次,分别打印 2,3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
function Component() {
const [a, setA] = useState(1)
console.log('a', a)
function handleClickWithPromise() {
Promise.resolve().then(() => {
setA((a) => a + 1)
setA((a) => a + 1)
})
}
function handleClickWithoutPromise() {
setA((a) => a + 1)
setA((a) => a + 1)
}
return (
<Fragment>
<button onClick={handleClickWithPromise}>{a} 异步执行</button>
<button onClick={handleClickWithoutPromise}>{a} 同步执行</button>
</Fragment>
)
// 当点击同步执行按钮时,两次 setA 都执行,但合并 render 了一次,打印 3
// 当点击异步执行按钮时,两次 setA 各自 render 一次,分别打印 2,3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24