大家好,我卡颂。
(资料图片)
稍微深入了解过useState的同学都知道 ——useState其实是预置了reducer的useReducer。具体来讲,他预置的reducer实现如下:
function basicStateReducer(state, action) { // $FlowFixMe: Flow doesn"t like mixed types return typeof action === "function" ? action(state) : action;}
那按理来说,useState与useReducer性能应该完全一致才对。但实际上,他们的性能并不一样。本文就来聊聊他们的细微差别。
一个严重的bug在v18之前,特定场景下,useReducer存在一个严重的bug。假设我们要挂载如下App组件:
bug复现地址[1]
function App() { const [disabled, setDisabled] = React.useState(false); return ( <>{`Disabled? ${disabled}`}> );}
通过点击按钮,可以切换disabled状态,并将disabled作为props传递给CounterReducer组件。
CounterReducer组件的实现如下:
function CounterReducer({ disabled }) { const [count, dispatch] = useReducer((state) => { if (disabled) { return state; } return state + 1; }, 0); return ( <>{`Count ${count}`}> );}
count状态初始为0,当disabled props为true时,点击「reducer + 1按钮」后count不会变化。
disabled为true时,多次点击后count仍显示0
当disabled props为false时,点击「reducer + 1按钮」后count会加1。
disabled为false时,点击后count加1
现在问题来了,当disabled props为true时(此时count为0),我们点击「reducer + 1按钮」5次,然后再点击「Disable按钮」(disabled props会变为false),此时count为多少呢?
按照代码逻辑,改变disabled对count不会造成影响,所以他应该保持原始状态不变(即为0)。
但在v18之前,他会变成5。
但是,如果我们用useState实现同样逻辑的useReducer:
function CounterState({ disabled }) { const [count, dispatch] = useState(0); function dispatchAction() { dispatch((state) => { if (disabled) { return state; } return state + 1; }); } return ( <>{`Count ${count}`}> );}
就能取得符合预期的效果。
所以说,useReducer的实现在特殊场景下是有bug的(v18之前)。
bug是如何产生的产生这个bug的原因在于React内部的一种被称为eager state的性能优化策略。
简单的说,对于类似如下这样的,即使多次触发更新,但状态的最终结果不变的情况(在如下例子中count
始终为0):
function App() { const [count, dispatch] = useState(0); return ;}
App组件是没有必要render的。这就省去了render的性能开销。
要命中eager state,有个严格的前提 —— 状态更新前后不变。
我们知道,React中有两种更新状态的方式:
传递新的状态。// 定义状态const [count, dispatch] = useState(0);// 更新状态dispatch(100)传递更新状态的函数。
// 定义状态const [count, dispatch] = useState(0);// 更新状态dispatch(oldState => oldState + 100)
那么,对于方式1,要保证状态不变很简单,只需要全等比较变化前后的状态,如果他们一致就能进入eager state策略。
对于方式2,就略微复杂点,需要同时满足2个条件:
「状态更新函数」本身不变。通过「状态更新函数」计算出的新状态也不变。比如,下述代码就同时满足2个条件,但如果将change放到App内就不满足条件1(App组件每次render时都会创建新的change函数):
// 状态更新函数本身不变function change(oldState) { // 新状态也不变 return oldState;}function App() { const [count, dispatch] = useState(0); // 状态更新函数每次render都会变化 // function change(oldState) { // 新状态不变 // return oldState; // } return ;}
类似的情况,在useState的实现中,虽然他是预置了reducer的useReducer,但他预置的reducer的引用是不变的,所以用他实现的文章开篇的例子可以命中优化策略。
useReducer在特定场景下的bug就与此相关。并不是说bug产生的原因是useReducer一定没命中优化策略,而是说相比于useState,他命中优化策略很不稳定。
v18之后的改变既然bug来源于不稳定的性能优化策略,在没有完美的解决方案之前,React是如何在v18中修复这个bug的呢?
答案是 —— 移除useReducer的eager state策略。也就是说,在任何情况下,useReducer都不再有useState存在的这个性能优化策略了。
这就导致在特定场景下,useReducer的性能弱于useState。
比如在这个v18在线示例[2]中,同样的逻辑用useState实现,不会有冗余的render,而useReducer会有。
总结在考虑性能优化时,如果useState与useReducer都能满足需要,或许useState是更好的选择。
参考资料[1]bug复现地址:https://codesandbox.io/s/vigorous-dhawan-mqv463。
[2]v18在线示例:https://codesandbox.io/s/blazing-cdn-pzcpz6?file=/src/App.js:509-519。
标签:
-
全球滚动:UseState与UseReducer性能居然有区别?
大家好,我卡颂。稍微深入了解过useState的同学都知道——useState其实是预置了reducer的useReducer。具体来讲,他预置的reduce
-
华泰柏瑞致远混合型证券投资基金增加代销机构的通知 全球观热点
华泰柏瑞基金管理有限公司(以下简称“本公司”)已于2023年2月23日公告,自2023年2月28日至2023年5月26日期间发行华泰柏瑞致远混合型证券投资基金(
-
每日报道:女生拖裤子拖内裤视频_女生拖裤子拖内裤
1、病情分析:你好,普通的体检怎么会全让你脱光你的衣服的。2、指导意见:何况你还是一个女孩,那是不可以进行检查的。3、就
-
好看的美甲款式学生_好看的美甲款式
1、爱美是女人的天性,这社会的发展,爱美的潮流席卷了市场,女孩子们在不断的追求美的过程中,从脸、身体、头发的美容,到现在
-
全球今头条!孙俪女儿海边腾空一字马,小孩子劈叉有什么好处?
“不知道说什么,就给大家劈个叉吧!”然而我根本不会劈叉!那些动不动就能下叉的人,他们究竟做了什么?劈叉对身体到底有什么好处?孙俪8...
-
天天快讯:马克龙参访中山大学,用中法双语发推:谢谢你,广州!法中友谊万岁!
法国总统马克龙于5日至7日对中国进行国事访问。马克龙来到了位于广州的中山大学参访,他也是首位到访广州的在任法国总统。北京时间8日凌晨0时
-
我国“教学三大奖”颁发 94岁顾明远获“教学大师奖”
中国青年报客户端重庆4月9日电(中青报·中青网记者耿学清)今天,第四届教学大师奖、杰出教学奖和创新创业英才奖颁奖典礼在
-
环球短讯!川渝检察机关:合力推进跨区域禁毒协作
正义网讯(记者张博 通讯员邬贤彬)日前,川渝检察禁毒协作启动仪式暨
-
注意 一中心附近道路通行有变 焦点快播
注意一中心附近道路通行有变
-
合同拒绝履行怎么处理|环球热消息
一、合同拒绝履行怎么处理合同拒绝履行的处理如下:守约方可以要求其赔偿违约金,或者承担继续履行、赔偿损失、采取补救措施等违
-
曾从钦:打造中国式现代化的中国酒业样本,需要找准三个点
4月7日,以“长周期新作为共美好”为主题的第十二届中国白酒T9峰会在安徽池州隆重召开。会上,白酒龙头企业齐聚一堂,就“十四五”期间白酒...
-
2023年4月9日1卢布可兑换多少人民币?
腾赚网为您提供卢布兑换人民币汇率最新价格详情。 2023年4月9日,货币兑换:1卢布=0 08296人民币。如:1卢布、2卢布、5卢布、10卢布、2
-
手机用久了待机时间会缩短,怎么延长电池的使用寿命呢? 环球观察
手机用久了待机时间会缩短,减少移动电源充电可以延长电池使用寿命,充电时不玩手机可以延长手机电池使用寿命,使用原装充电器可以延长电池使
-
【世界新要闻】27英寸是多少厘米_27英寸
1、英寸是英国标准,是长度单位。2、1英寸=2 539999918厘米寸是中国古代常用长度标准1寸=3 3
-
配置高可用Eureka Server集群
在生产环境中,我们通常需要配置一个高可用的EurekaServer集群。为此,我们需要启动多个EurekaServer实例,并将它们组成一个集群。在Spri
-
环球滚动:女生生日礼物送什么好
关于送她喜欢什么就送什么,女生喜欢什么,再过生日礼物也不能太贵,送的太寒酸,女生喜欢什么就买什么东西了。送有创意的礼物
-
【天天热闻】桃源路_关于桃源路简述
1、桃源路是一条在郑州市非常著名的街道。2、全长2000米,北临郑州大学,南临郑州市二中,郑州市桃源中学(前河南省交通学校、现河南交通职业
-
焦点快播:宁德师范学院工会获命名“2023年福建省巾帼文明岗”
日前,福建省妇女联合会印发《福建省妇联关于命名2023年福建省巾帼文明岗的决定》,200个集体(岗组)获命名2023年福建省巾帼文明岗,宁德师范
-
绽放你的美!2023中国品牌节女性论坛在郑州开幕|世界新要闻
最是一年春好处,人间四月“郑”当时。4月8日,以“绽放你的美”为主题的2023中国品牌节第十六届女性论坛(以下简称202
-
安阳安林公路凌晨发生两起货车相撞事故 1人受伤4车受损|焦点播报
据河南安阳市公安局殷都分局4月8日通报,4月8日2时许,在安林公路许家沟乡五里庙村路段发生两起货车相撞交通事故,事故共造
-
焦点访谈丨直播带岗“职”等你来-每日快看
直播带货,您一定知道,那您听说过直播带岗吗?最近,直播带岗这种新的数字化招聘方式蓬勃兴起,迅速成为一个重要的招聘渠道。从蓝领群
-
全国春播粮食面积已达1亿亩 智能育苗提高生产
农业农村部最新农情调度显示,截至目前,全国已春播粮食1亿亩,完成意向面积的10 5%,进度同比相当。吉林省四平市梨树县农机专业合作社农机手
-
世界短讯!红墙股份董秘回复:关于公司经营业绩和财务状况情况说明请关注公司在官方指定媒体披露的相关公告
红墙股份(002809)04月08日在投资者关系平台上答复了投资者关心的问题。
-
环球快资讯:河南焦作:公积金贷款购房单笔最高额度调至60万元,增加贷款次数
河南焦作:公积金贷款购房单笔最高额度调至60万元,增加贷款次数
-
每日视点!德语新正字法精要
1、《德语新正字法精要》是2004年上海外语教育出版社出版的图书。2、作者是华宗德。本文到此分享完毕,希望对大家有所
-
恩格斯自然辩证法全文阅读_恩格斯自然辩证法|天天观察
1、恩格斯在《自然辩证法》中,以高瞻远瞩的领袖气质,提出对思想家的理解,思想家不仅对大自然有深刻了解,还要对自然有敬畏之
-
末世求生录周御龙_末世求生录
1、浮世惊华之邪皇谋妻2、作者:午日阳光3、小说简介:4、她身边总跟着一只狼,因为它像某人。他走到哪里都抱着一只狐,因
-
锚定大湾区发展版图 绿城管理携手前海润禾、勤诚达开创多方共赢新局面-微资讯
2023年4月7日,绿城管理(09979)与大湾区知名本土品牌开发商勤诚达集团及拥有深圳国企背景的前海润禾,在深圳签署《全面战略合作协议》。三方将
-
即时焦点:纵论天下丨美方再炒“实验室泄漏论”居心叵测
日前,华盛顿政客们再次大肆翻炒“实验室泄漏论”,炮制虚假信息,其抹黑中国的手段之拙劣、用心之险恶,令世人不齿。资料图片:这是1月20...
-
ST开元(300338.SZ)拟参设产业投资基金 布局、培育及投资新能源领域
智通财经APP讯,ST开元(300338 SZ)公告,公司全资子公司长沙麓元匠为新能源科技有限公司(“麓元匠为”)拟借助湖南中财开元私募股权基金管理有