在React中更新状态,一般的写法都是this.setState({a:1})
,而非Vue那样this.a = 1
。并且,如果在如下场景:
state = { count: 0,};componentDidMount() { this.setState({ count: this.state.count + 1, }); console.log("console: " + this.state.count); }render(){ console.log("render: " + this.state.count);}
打印结果为
console:0render:1
所以,从表现上看,setState
是异步的。
其实,这只是React的障眼法。
setState
是同步执行的!但是state并不一定会同步更新(异步更新和同步更新都存在)
1. 对比Vue
Vue的数据更新是基于event-loop
机制(是更新,不是数据双向绑定)。

Vue在侦听到数据变化后,会开启一个队列,并缓冲在同一事件循环中发生的所有数据变更(如果同一个 watcher 被多次触发,只会被推入到队列中一次)。然后,在下一个事件循环Tick/微任务中,Vue 刷新队列执行实际工作。(事件循环参考《宏任务和微任务到底是什么?》)
2. React.setState()
中的异步更新
setState()
中有个特别重要的布尔属性isBatchingUpdates
(默认为false,),它决定了state
是同步更新还是异步更新。
调用栈如下(涉及到React事务机制,可以参考文章《React进阶篇(四)事务》):

setState
只在合成事件和钩子函数中是“异步更新”的。
异步更新的背后,是同步代码处理("合成事件和钩子函数"的调用在"更新"之前)。
异步是为了实现批量更新的手段,也是React性能优化的一种方式。
2. React.setState()
中的同步更新
当然,也是有办法同步获取state
更新后的值:
setTimeout
等异步操作中调用setState函数- DOM原生事件
- 利用
setState
回调函数 - 函数式
setState
用法
前两个都比较好理解,因为没有前置的batchedUpdate
调用,所以isBatchingUpdates
为false。不会开启批量更新模式,那么,在上面的调用栈图示里面,会直接走到事务更新。
后面两个方法,是React本身提供的。要注意的是,setState
回调函数要在render函数被重新执行后才执行。
下面有一道题目,试试做吧!
import React from "react";class TestView extends React.Component { state = { count: 0, }; componentDidMount() { this.setState({ count: this.state.count + 1, }); console.log("console: " + this.state.count); this.setState({ count: this.state.count + 1 }, () => { console.log("console from callback: " + this.state.count); }); this.setState( (prevState) => { console.log("console from func: " + prevState.count); return { count: prevState.count + 1, }; }, () => { console.log("last console: " + this.state.count); } ); } render() { console.log("render" + this.state.count); return <h4>test</h4>; }}export default TestView;
原著是一个有趣的人,若有侵权,请通知删除
还没有人抢沙发呢~