React中setState同步异步的相关问题是怎样的
Admin 2022-07-07 群英技术资讯 311 次浏览
在 React 的类式组件中,我们可以使用setState方法更新state状态。但有些时候使用setState之后,得不到最新的数据。
其实 React 中setState本身执行的过程和代码是同步的,只是因为 React 框架本身的性能优化机制而导致的。React 中合成事件和生命周期函数的调用顺序在更新之前,导致在合成事件和生命周期函数中无法立刻得到更新后的值,形成了异步的形式。
假如在一个合成事件中,循环调用了setState方法n次,如果 React 没有优化,当前组件就要被渲染n次,这对性能来说是很大的浪费。所以,React 为了性能原因,对调用多次setState方法合并为一个来执行。当执行setState的时候,state中的数据并不会马上更新。
前面已经说到,在 React 的合成事件和生命周期函数中直接调用setState,会表现出异步的形式。
除此之外,如果越过 React 的性能优化机制,在原生事件、setTimeout中使用setState,就会表现出同步的形式。
在 React 中直接使用的事件,如onChange、onClick等,都是由 React 封装后的事件,是合成事件,由 React 管理。那么由于性能优化的机制,在合成事件中直接调用setState,将表现出异步的形式。
如下代码,在合成事件onClick中,直接将state中的count加1,并在此之后打印count的值,结果第一次点击按钮时,会打印出0,而不是最新的1。
state = { count: 0 }; add = () => { this.setState({ count: this.state.count + 1 }); console.log(this.state.count); // 0 }; render() { return ( <> <div>当前计数:{this.state.count}</div> <button onClick={this.add}>add</button> </> ); }
生命周期函数也是由 React 所管理,在生命周期函数中直接调用setState,也会表现出异步的形式。
如下代码,在生命周期componentDidMount函数中,将state中的count加1,并在此之后打印count的值,结果打印出0,而不是最新的1。
state = { count: 0 }; componentDidMount() { this.setState({ count: this.state.count + 1 }); console.log(this.state.count); // 0 } render() { return ( <> <div>当前计数:{this.state.count}</div> <button>add</button> </> ); }
setState本身执行的过程是同步的,使用原生事件,绕过 React 的管理,将表现出同步的形式。
如下代码,通过id获取到 DOM 元素,用原生方法绑定点击事件。在点击事件中,将state中的count加1,并在此之后打印count的值,结果会打印最新的count值1。
state = { count: 0 }; componentDidMount() { const btn = document.getElementById('btn'); btn.onclick = () => { this.setState({ count: this.state.count + 1 }); console.log(this.state.count); // 1 }; } render() { return ( <> <div>当前计数:{this.state.count}</div> <button id="btn">add</button> </> ); }
如下代码,在生命周期componentDidMount函数中写了一个定时器setTimeout,在setTimeout内部将state中的count加1,并在此之后打印count的值,结果会打印最新的count值1。
setState虽然也是写在生命周期componentDidMount函数中的,但并不是直接写在componentDidMount里,而是套了一层setTimeout。这样,setState就表现出同步的形式。
state = { count: 0 }; componentDidMount() { setTimeout(() => { this.setState({ count: this.state.count + 1 }); console.log(this.state.count); // 1 }, 0); } render() { return ( <> <div>当前计数:{this.state.count}</div> <button>add</button> </> ); }
无论setState的对象式写法,还是函数式写法,都有第二个参数,为可选的回调函数,这个回调函数在状态更新完毕、界面也更新后(render调用后)才被调用。
如下代码所示,setState虽然直接在componentDidMount中调用,但在setState的回调函数中打印count的值,得到了最新的值1,因为回调函数在状态更新完毕后才被调用,当然能得到最新的count了。
state = { count: 0 }; componentDidMount() { this.setState({ count: this.state.count + 1 }, () => { console.log(this.state.count); // 1 }); } render() { return ( <> <div>当前计数:{this.state.count}</div> <button>add</button> </> ); }
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。
猜你喜欢
在面向对象语言中,接口是一个很重要的概念,它是对行为的抽象。接口也叫 interface 。在 js 中没有接口这个概念,它是新增的。该如何定义呢?下面来一起学习吧
如何现实小程序消息推送?这篇文章主要给大家介绍微信小程序消息推送的实现,文本代码具有一定的借鉴价值,有需要的朋友可以参考参考,下面就跟随小编一起来了解一下吧。
目录如何清除浏览器历史栈问题vue返回首页后如何清空路由需求一:从首页点击路由到A页面需求二:把浏览器的记录返回指定的页面如何清除浏览器历史栈问题需要跳转好几个页面进行表单提交,提交完之后,跳转回首页,返回上一页,发现还可以返回上一级页面路由//可以拿到历史记录栈,清空栈let routeHistory=history
利用JavaScript实现仿QQ个人资料卡效果 目录 前言 思路 实现代码 HTML CSS 背景音乐 JavaScript 最终效果 前言 最近在学习前端的知识,无意间发现QQ 那个个人资料卡还挺好看的,就想着自己能不能照着原版搞出一个高仿出来,话不多时直接开始先睡上一觉,找找灵感,睡醒来又饿了,出去吃个饭,回来天tm都黑了,哈哈哈哈,金今天又是摆烂的一天,啊啊啊,不行至少今天这篇博客得写个前言部分…于是乎我们来到第二天,开始干(要干啥来着,幸亏昨天还写了个标题,要不然都忘了——HTML+CSS+JS实现仿QQ个人资料卡) 不多逼逼直接上干
这篇文章主要介绍了解决vue项目本地启动时无法携带cookie,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
成为群英会员,开启智能安全云计算之旅
立即注册Copyright © QY Network Company Ltd. All Rights Reserved. 2003-2020 群英 版权所有
增值电信经营许可证 : B1.B2-20140078 粤ICP备09006778号 域名注册商资质 粤 D3.1-20240008