setState如何同步,可以视同setTimeout(……, 0)跳出React的setState的事务控制
参考:
解决问题:如何让React的setState变为同步
btnClick1
两次同时给state.a加1.在React控制的时候,始终多次运行,只会加一次,而且因为setState不同步,console的输出始终先于setState
btnClick1=()=>{ this.setState({ a: this.state.a + 1 }); this.setState({ a: this.state.a + 1 }); console.log('点击时的a的值为:',this.state.a); }
btnClick3
两次同时给state.a加1.在React控制的时候,始终多次运行setState,会执行多次,而且因为setState跳出了Reactde异步控制,console的输出就会取到setState之后的值。
btnClick3 = ()=>{ setTimeout(() => { this.setState({ a: this.state.a + 1 }); this.setState({ a: this.state.a + 1 }); console.log('点击时的a的值',this.state.a); },0) }
结论(React的setState批量更新原理)
异步:React 会先找到我们注册的 vnode 和 vnode 内的对应事件,从而在执行前,先把 isBatchingUpdate这个变量打开。只要我们的方法没完成,由于变量锁的存在,就会一直让我们的修改只停留在更新中状态内,一直不会更新到实际的 state
上。直到我们的方法执行完,事务的后置函数就会关闭我们的 isBatchingUpdate,并执行渲染操作,至此整个批量更新就完成了。
同步:setTimeout 里面会同步是由于 setTimeout会把里面的函数放到下一个宏任务内,这样就刚好跳出了事务的控制,就会显示出同步更新的情况。这里就是Javascript 的 Event-loop 机制;另外,在原生事件中,绕过了React,不会触发isBatchingUpdates变量的改变,所以也会同步进行更新渲染
完整代码:
菜鸟教程提供的运行环境:替换为下列代码,可以再页面和F12控制台(mac:option_command_i)查看运行结果
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>菜鸟教程 React 实例</title> <script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script> <script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script> <script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script> </head> <body> <div id="example"></div> <script type="text/babel"> class App extends React.Component{ constructor(props){ super(props); } state = { a: 1 } componentDidMount(){ console.log('a的初始值为:',this.state.a); } btnClick1=()=>{ this.setState({ a: this.state.a + 1 }); this.setState({ a: this.state.a + 1 }); console.log('点击时的a的值为:',this.state.a); } sState = ()=>{ this.setState({ a: this.state.a + 1 }); this.setState({ a: this.state.a + 1 }); } btnClick2=()=>{ this.sState(); console.log('点击时的a的值为:',this.state.a); } btnClick3 = ()=>{ setTimeout(() => { this.setState({ a: this.state.a + 1 }); this.setState({ a: this.state.a + 1 }); console.log('点击时的a的值',this.state.a); },0) } render(){ return ( <div> <div>hello william</div> <button onClick={this.btnClick2}>点击按钮</button> <div>{this.state.a}</div> </div> ) } } ReactDOM.render( <App />, document.getElementById('example') ); </script> </body> </html>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
2018-12-06 Android进程优先级和垃圾回收机制