七爪源码从新的React文档中查看useEventpolyf
今年夏天的一个好日子,React传奇人物DanAbramov为期待已久的useEvent钩子发布了一个polyfill。介意我们看看吗?
一点上下文
如果您最近没有关注新闻,您可能错过了useEvent的RFC。长话短说,以下是React团队对此的评价:
我们怀疑useEvent是Hooks编程模型中一个基本缺失的部分,它将提供正确的方法来修复过度触发效果,而不会出现像跳过依赖项这样容易出错的hack。
实际上,在引入useEvent之前,您可能很难编写某些效果,而不必忽略数组中的依赖关系或对所需行为做出妥协。
以RFC中的这个例子为例。目标是在用户访问页面时记录分析:functionPage({route,currentUser}){useEffect((){logAnalytics(visitpage,route。url,currentUser。name);},〔route。url,currentUser。name〕);。。。}
当路由更改时,会记录一个带有路由URL和用户名的事件。现在假设用户在个人资料页面上,她决定编辑她的姓名。效果再次运行并记录一个新条目,这不是我们想要的。
使用useEvent,您可以从效果中提取事件:functionPage({route,currentUser}){StableidentityconstonVisituseEvent(visitedUrl{logAnalytics(visitpage,visitedUrl,currentUser。name);});useEffect((){onVisit(route。url);},〔route。url〕);Rerunsonlyonroutechange。。。}
日志分析现在是为了响应由路由更改触发的事件而完成的。
事件处理程序(onVisit)是通过useEvent创建的,它返回一个稳定的函数。这意味着即使组件重新渲染,useEvent返回的函数也将始终相同(相同的标识)。正因为如此,它不再需要作为依赖传递给useEffect
您可以在RFC本身中阅读有关useEvent的其他示例和很酷的内容,例如在使用站点包装事件。但在我写这篇文章时,useEvent仍在进行中。所以在它发布之前,人们仍然会想知道从他们的依赖数组中省略依赖是否安全。。。。。。
。。。。或者他们可以开始使用DanAbramov在新的React文档中发布的shim
一个shim诞生了
如果你真的没有关注新闻,那么你可能错过了React团队今年一直忙于重写他们的文档网站的事实(如果你来自未来,这里是2022年)。
它仍处于测试阶段,但已经比旧版本好得多。我希望所有文档都和这个一样好。我一直提到丹阿布拉莫夫的原因是他是主要作者(国王万岁)。
效果在这些新文档中有一个特殊的部分。可能是因为自React16。8发布以来,包括我自己在内的人们一直在错误地使用它们(或过度使用它们)。或者可能是因为当人们注意到升级到React18后,他们的1,000个效果开始在StrictMode下运行两次时,他们开始抱怨。
因此,毫不奇怪,您会在新文档中找到多达5页专门介绍效果的页面!您还将详细了解useEvent如何将您从依赖地狱中拯救出来。但当你开始接触它时,你会偶然发现以下陷阱之一:
幸运的是,在这个炎热的夏天的一个美好的一天,除了这个大的免责声明之外,没有太多解释,在示例和挑战中添加了一个polyfill:import{useRef,useInsertionEffect,useCallback}fromreact;TheuseEventAPIhasnotyetbeenaddedtoReact,sothisisatemporaryshimtomakethissandboxwork。Yourenotexpectedtowritecodelikethisyourself。exportfunctionuseEvent(fn){constrefuseRef(null);useInsertionEffect((){ref。currentfn;},〔fn〕);returnuseCallback((。。。args){constfref。current;returnf(。。。args);},〔〕);}
有趣的。我不了解你,但我忍不住想看看shim里面的代码。即使这只是一个临时的,我也不希望自己写!你呢?
我是这么想的。
然后让我们从第7行开始,这里声明了useEventshim。正如预期的那样,钩子在参数中接收一个名为fn的回调函数,就像RFC中的那样:exportfunctionuseEvent(fn){
接下来,使用useRef声明一个引用,该引用最初包含null值(第8行):constrefuseRef(null);
接下来是有趣的部分:参考(ref)是从效果中设置的,而不是在fn更改时运行(第911行):useInsertionEffect((){ref。currentfn;},〔fn〕);
这不是任何一种效果:React团队选择使用在React18中引入的插入效果。
如果你不知道,React中有几种效果:普通效果(由useEffect触发)、布局效果(useLayoutEffect)和插入效果(useInsertionEffect)。
它们中的每一个都在组件生命周期的不同阶段触发。首先是插入效果(在应用DOM突变之前),然后是布局效果(在DOM更新之后),最后是普通效果(在组件完成渲染之后),import{useEffect,useInsertionEffect,useLayoutEffect}fromreact;import。styles。css;exportdefaultfunctionApp(){useEffect(()console。log(useEffect),〔〕);useInsertionEffect(()console。log(useInsertionEffect),〔〕);useLayoutEffect(()console。log(useLayoutEffect));constsetRef(e)console。log(setRef);return(pref{setRef}Opentheconsoletoseeinwhichorderthevariouseffectsrun{}spanroleimgarialabelfingerpointingdownspan);}
您应该在控制台中看到以下输出:
useInsertionEffect
setRef
useLayoutEffect
useEffect
这与我们之前所说的一致。我们还可以看到,插入效果的触发时间与React设置引用的时间差不多,更重要的是,在布局效果之前。
RFC中的详细设计规定:
在所有布局效果运行之前切换〔event〕处理程序的当前版本。这避免了用户态版本中存在的陷阱,即一个组件的效果可以观察到另一个组件状态的先前版本。不过,切换的确切时间是一个悬而未决的问题(在底部列出了其他悬而未决的问题)。
现在可以理解为什么将引用设置在插入效果而不是任何其他类型的效果上。在布局效果内或以后运行的代码期望调用更新的引用。所以需要先更新参考。
使用插入效果当然不是万无一失的。可以尝试在另一种插入效果中使用事件处理程序。在这种情况下,参考可能还不是最新的。这就是为什么useEvent不能在用户空间中安全实现的原因。React内部的未来实现将解决这个问题。
但让我们回到垫片。我再贴一次,这样更容易理解:import{useRef,useInsertionEffect,useCallback}fromreact;TheuseEventAPIhasnotyetbeenaddedtoReact,sothisisatemporaryshimtomakethissandboxwork。Yourenotexpectedtowritecodelikethisyourself。exportfunctionuseEvent(fn){constrefuseRef(null);useInsertionEffect((){ref。currentfn;},〔fn〕);returnuseCallback((。。。args){constfref。current;returnf(。。。args);},〔〕);}
最后一部分涉及useCallback返回的函数(第1215行):returnuseCallback((。。。args){constfref。current;returnf(。。。args);},〔〕);
该回调没有任何依赖项〔〕(第15行),因此它只创建一次。因此,useCallback总是返回相同的函数。正因为如此,垫片返回一个满足规范的稳定函数。
现在是回调本身。我们看到:
1。返回useCallback((。。。args){
它接受一个可变的参数列表(代码没有对处理程序接受的参数数量做出任何假设):
2。常量f参考电流;
它访问ref的当前值,其中包含最新的fn函数(感谢效果行10中的代码):
3。返回f(。。。args);
最后,它调用该函数,转发收到的参数
在这里,我们有一个始终保持最新的稳定事件处理程序!而且由于事件处理程序是稳定的,因此无论是否将其包含在效果的依赖数组中都没有关系:它永远不会导致效果再次自行运行。
但为什么它会起作用?
是的,我很确定每个人仍然不清楚为什么这确实有效。事件处理程序如何始终是最新的?最新,我不仅仅意味着它的引用是最新的,还意味着它可以在运行时访问新值。
让我们回到RFC中的示例:functionPage({route,currentUser}){StableidentityconstonVisituseEvent(visitedUrl{logAnalytics(visitpage,visitedUrl,currentUser。name);});useEffect((){onVisit(route。url);},〔route。url〕);Rerunsonlyonroutechange。。。}
为什么当效果调用onVisit时,currentUser。name是最新的,即使我们没有在任何地方指定它作为依赖项?
好吧,每次组件渲染时,我们都会使用新的箭头函数visitedUrl{。。。}调用useEvent。该函数访问currentUser。name,该名称在组件范围的上层定义。这就是我们所说的闭包。因此,该函数会在渲染组件时捕获currentUser。name的值。
由于我们使用的是React,我们知道组件会在其props更改时重新渲染。这就是为什么每次组件渲染时我们都有一个新的update函数,useEvent负责将其存储在它的ref中。然后,每当调用事件处理程序(onVisit)时,代码都会调用存储在ref中的函数,该函数捕获组件中的最新值。
当您尝试用它们的值替换属性时,更容易理解:
第一次渲染
假设该组件是使用以下内容呈现的:Page({route:{url:profile},currentUser:{name:Dan},});
当它发生时,您可以想象使用一个函数调用useEvent,其中currentUser。name被Dan替换:constonVisituseEvent(visitedUrl{logAnalytics(visitpage,visitedUrl,Dan);});
在这个表示中,visitedUrl{logAnalytics(visitpage,visitedUrl,Dan);}是存储在useEvent中的ref中的内容。
因此,当效果使用它所依赖的route。url调用onVisit时,实际上使用以下值调用logAnalytics:logAnalytics(visitpage,profile,Dan);
第二次渲染
现在想象一下,丹将他的名字改为瑞克(对不起丹)。React使用以下命令重新渲染组件:Page({route:{url:profile},currentUser:{name:Rick},});
再次调用useEvent,这次是用一个函数将currentUser。name替换为Rick(更新后的值):constonVisituseEvent(visitedUrl{logAnalytics(visitpage,visitedUrl,Rick);});
useEvent再次使用visitedUrl{logAnalytics(visitpage,visitedUrl,Rick);}。
但是由于route。url没有改变,所以效果没有运行,因此onVisit也没有被调用。不记录任何分析。
第三次渲染
然后,DanRick导航到主页。组件再次渲染:Page({route:{url:home},currentUser:{name:Rick},});
useEvent再次调用了一个函数,其中currentUser。name被Rick替换:constonVisituseEvent(visitedUrl{logAnalytics(visitpage,visitedUrl,Rick);});
尽管currentUser。name的值与之前(Rick)相同,但传递给useEvent的函数严格来说仍然是一个新函数。它们是不同的实例,因此它们具有不同的身份(如果我们将该函数与前一个渲染中的函数进行比较,Object。is将返回false)。所以useEvent再次更新它的ref。我们不在乎!开销可以忽略不计。
最后,效果再次运行,因为它的依赖关系(route。url)发生了变化。这意味着这次使用home调用onVisit,然后调用logAnalytics:logAnalytics(visitpage,home,Rick);
正如您所期望的那样!
附带说明一下,有趣的是,在此示例中,路由URL是作为参数传递给onVisit事件的,而不是直接在处理程序内部引用(就像我们对currentUser。name属性所做的那样)。这是一个重要的区别,因为这意味着我们将在效果运行时记录路由URL。如果我们在事件处理程序中使用了logAnalytics(visitpage,route。url,currentUser。name),我们将始终记录路由URL的最新值。
在这种特殊情况下,它没有太大区别,因为效果中的代码是同步的。但如果onVisit已被调用以响应异步方法,则传递给函数的路由URL的值将是效果运行时的值,它可能不再是最新的route。url。
如果您喜欢您阅读的内容,请随时关注我以获取更多信息!
关注七爪网,获取更多APP小程序网站源码资源!
C罗快速转会真正的原因,不能晋级欧冠只是一个借口克里斯蒂亚诺罗纳尔多突然要求转会的原因已经揭晓。欧冠也是一个借口。真正原因是因为他的转会市场请求被曼联拒绝了。英国《镜报》11日(韩国时间)报道称,由于新任主帅埃里克滕哈……
绝区零是崩坏三的进阶版本吗?米哈游真的很懂游戏绝区零你好,欢迎来到Holdon2099的绝区零世界。米哈游的新游戏《绝区零》终于开始封测了,和大多数玩家一样,小编也没得到测试资格,一定是漏发了!还好有朋友拿到了,就只……
热血传奇如今的复古传奇还有曾经的初心吗?你还愿意为此买单吗当年第一次玩传奇到现在也有十多年了那个时候玩传奇是因为跟风大家都在玩我也就玩一下这么久的时间过去了现在讲到传奇就是一种经典了不过现在的传奇很多没有当年那种经典……
日本人长寿的原因和食日本人长寿的原因日本人长寿的原因有几个理由。厚生劳动省(相当于国内人力资源与社会保障部卫生部)发表的2018年日本人平均寿命数据显示,男性81。25岁,女性87。32岁,……
长期不吃晚饭?你可能会迎来这3大问题,建议尽早改掉为了促进健康,饮食技巧需要掌握好,了解相关的饮食原则,正确遵循后身体才能维持健康。然而,很多人听信谣言,认为不吃晚餐对健康有促进作用,可以避免消化压力增大,获取过多能量让……
让器官提前衰老!这些坏习惯,你占了几个?每个器官都有使用期限,而身体是一个需要各个器官协助运转的有机整体,哪一部分出了问题都不会是小事!如果不想让身体器官提前衰老,以下这些习惯一定要拒绝!吃撑了易增加心脏负担……
中国古代10大旅行家中国古人曾经到达过澳大利亚吗?探险家,也可以说是旅行家,航海家,他们通过各种各样的方式去远方去旅行,给人们带来新的知识,开阔人们的眼界。历史上,欧洲出现了马可波罗、迪亚士、达伽马、哥伦布、麦哲伦、雷迪克等著……
德国慕尼黑法院对OPPO发出手机禁售令IT之家8月8日消息,据Wirtschaftswoche报道,OPPO和一加手机正在从德国地区消失,至少目前是这样。OPPO可能会彻底退出德国市场,其他品牌也都受到专利诉讼的影……
靠夫妻肺片出圈的紫燕百味鸡冲刺A股,高管客户系自家人南都湾财社记者陈盈珊靠夫妻肺片出圈的紫燕百味鸡,要上A股了。近期,上海紫燕食品股份有限公司(以下简称紫燕食品)首发过会,有望成为佐餐卤味第一股。届时,原先以绝味食品(60351……
42打哭日本伊藤美诚平野美宇,6连胜强势夺冠,何卓佳大爆发北京时间7月24日消息,2022年世界乒联WTT夏季系列赛圆满落幕。在WTT支线赛布达佩斯站女单决赛中,中国名将何卓佳42战胜日本选手桥本帆乃香,夺得一个分量沉甸甸的冠军。值得……
生活中有些人工合成的垃圾食品,孩子吃着挺香,对身体伤害却很大随着人们生活水平的提高,认知能力的增强。越来越多的人开始注重饮食安全,特别是一些家长开始重视孩子的饮食,对一些垃圾食品也开始在意起来。毕竟孩子是自己的心头肉,不光要吃的好,还要……
放弃抄书打卡入口理想一旦被付诸行动,就会变得神圣。有理想在的地方,地狱就是天堂。不要只因一次失败,就放弃原来决心想要达到的理想。看到很多的朋友,放弃了自己曾经的理想,着……
城乡居民传来好消息!基础养老金将迎来上调,究竟涨了多少?最近一段时间,大家都在关注各地退休职工的养老金调整通知,因为7月份,城镇退休职工的养老金都迎来了新一轮的调整,不过你知道么?除了城镇职工的养老金迎来调整外,城乡居民养老金也同样……
山东70河北创队史最大分差纪录,克雷桑传射,刘彬彬双响中超第13轮比赛,河北对阵山东泰山。上半场,金敬道开场不久就头槌破门,随后莫伊塞斯远射造险,费莱尼破门扩大比分,仅仅2分钟后,刘彬彬就单刀再下一城,张俊哲伤退,张威造险。下半场……
好大的口气!美国正面警告中国敢帮俄罗斯,中芯国际就等着关门美国商务部长雷蒙多8日警告称,如果中国公司继续无视美国对俄罗斯实施的制裁而与俄方展开深度合作,那么美国商务部会对中国公司采取毁灭性行动。在接受媒体采访时,雷蒙多表示当前中国企业……
高速换刀,势在必行CBA刚刚公布的得分榜,前十位球员里,八名是各队的小外援。当下,后场小外援这个点的火力如何,直接决定了球队的进攻水平和胜率。强如苏州的布莱克尼、天津的杰佛森、同曦的皮特森……
今日油价消息今天9月26日,全国加油站929598号汽油价格今天是2022年9月26日星期一,前几天油价刚刚完成下跌,转眼间又来到新的计价日周期,今天是油价调整的第三个工作日,截止目前全国油价又一次迎来大幅下跌,已经连续四个工作日的下跌……
长期运动和不运动的孩子,大脑差别巨大上个周末,我们4家人带了6个娃去江门儿童公园玩。这个公园最大的亮点是全程靠人力,各种大中型设备让娃去攀爬、穿梭、摇晃、蹦跳,每个在这里玩的孩子不湿透几件衣服都不肯回家。……
抓不住灵感也要写作清晨醒来,大脑休息一晚,情绪沉淀一夜,有好多话急不可耐地想诉说。打开《老子通释》读一章,有感悟要写。这时想说想写的灵感寄存在心间。早起,在公园领爱人锻炼,他生病后,身体康……
APP越用越膨胀,你的手机存储还好吗?来源:中国新闻网中新网10月13日电(中新财经记者吴涛)你的手机存储空间还够用吗?近日,手机存储焦虑话题登上微博热搜,网友纷纷吐槽APP占用空间大,动不动几个GB就没了。……
比特币(BTC)和以太坊(ETH)卡住了加蜜货碧行业随着时间的推移不断发展。随着这些持续的变化,我们也可以看到曾经主导市场的加蜜货碧现在如何面临确保其存在的挑战。这就是比特碧(BTC)和以太坊(ETH)等曾经主导市场……
佟大为一个在屏幕上光鲜亮丽的明星,背后竟有着不为人知的故事一hr佟大为,一九七九年二月三日出生于辽宁省抚顺市新抚区一个普通的家庭里,父亲佟振军是一名威风凛凛的交警,每天骑着带挎斗的三轮摩托车上班,母亲白洁在一家图书馆上班。还有个姐姐,……
新视野号在柯伊伯带,拍下的真实照片,无法想象这是外太阳系新视野号从发射至今已经过去十多年,它给人类带来的新发现远不止证实遥远边际地带这么简单。探测器的发射往往会伴随着科学理论的验证,因此新视野号并不是一台单纯的观光探测器。那么……
最适合露营的车辆改装有哪些?近期,近郊露营突然火了起来,一时间,各大户外品牌商店,帐篷、天幕、折叠桌椅等等卖断了货。春暖花开的时节,相信每个人的朋友圈里都能看到有人发的露营照片。受到疫情的影响,去往……