,大家好,我卡颂。,每个框架由于实现原理的区别,都会有些独特的概念。比如:,在React中,有一个「非常容易」被误用的API —— useEffect,今天要介绍的Effect Event就属于由useEffect衍生出的概念。,本文一共会涉及三个概念:,首先来聊聊Event与Effect。useEffect容易被误用也是因为这两个概念很容易混淆。,在下面的代码中,点击div会触发点击事件,onClick是点击回调。其中onClick就属于Event:,Event的特点是:「是由某些行为触发,而不是状态变化触发的逻辑」。,比如,在上述代码中,onClick是由「点击事件」这一行为触发的逻辑,num状态变化不会触发onClick。,Effect则与Event相反,他是「由某些状态变化触发的,而不是某些行为触发的逻辑」。,比如,在下述代码中,当title变化后document.title会更新为title的值:,上述代码中useEffect的逻辑就属于Effect,他是由title变化触发的。除了useEffect外,下面两个Hook也属于Effect:,现在问题来了:Event与Effect的概念完全不同,为什么会被误用?,举个例子,在项目的第一个版本中,我们在useEffect中有个初始化数据的逻辑:,随着项目发展,你又接到一个需求:提交表单后更新数据。,为了复用之前的逻辑,你新增了options状态(保存表单数据),并将他作为useEffect的依赖:,现在,提交表单后(触发onSubmit回调)就能复用之前的数据初始化逻辑。,这么做实在是方便,以至于很多同学认为这就是useEffect的用法。但其实这是典型的「useEffect误用」。,仔细分析我们会发现:「提交表单」显然是个Event(由提交的行为触发),Event的逻辑应该写在事件回调中,而不是useEffect中。正确的写法应该是这样:,上述例子逻辑比较简单,两种写法的区别不大。但在实际项目中,随着项目不断迭代,可能出现如下代码:,届时,很难清楚fetchData方法会在什么情况下执行,因为:,所以,在React中,我们需要清楚的区分Event与Effect,也就是清楚的区分「一段逻辑是由行为触发的,还是状态变化触发的?」,现在,我们已经能清楚的区分Event与Effect,按理说写项目不会有问题了。但是,由于「Effect的机制问题」,我们还面临一个新问题。,假设我们有段聊天室代码,当roomId变化后,要重新连接到新聊天室。在这个场景下,聊天室的断开/重新连接依赖于roomId状态的变化,显然属于Effect,代码如下:,接下来你接到了新需求 —— 当连接成功后,弹出「全局提醒」:,,「全局提醒」是否是黑暗模式,受到theme props影响。useEffect修改后的代码如下:,但这段代码有个严重问题 —— 任何导致theme变化的情况都会导致聊天室断开/重新连接。毕竟,theme也是useEffect的依赖项。,在这个例子中,虽然Effect依赖theme,但Effect并不是由theme变化而触发的(他是由roomId变化触发的)。,为了应对这种场景,React提出了一个新概念 —— Effect Event。他指那些「在Effect内执行,但Effect并不依赖其中状态的逻辑」,比如上例中的:,我们可以使用useEffectEvent(这是个试验性Hook)定义Effect Event:,在上面代码中,theme被移到onConnected(他是个Effect Event)中,useEffect虽然使用了theme的最新值,但并不需要将他作为依赖。,useEffectEvent的实现并不复杂,核心代码如下:,其中ref变量保存「callback的引用」。对于上述例子中:,ref保存对如下函数的引用:,useEffectEventImpl方法接受ref和callback的最新值为参数,在useEffect执行前会将ref中保存的callback引用更新为callback的最新值。,所以,当在useEffect中执行onConnected,获取的就是ref中保存的下述闭包的最新值:,闭包中的theme自然也是最新值。,仔细观察下useEffectEvent的返回值,他包含了两个限制:,第一个限制比较明显 —— 下面这行代码限制useEffectEvent的返回值只能在useEffect回调中执行(否则会报错):,另一个限制则比较隐晦 —— 返回值是个全新的引用:,如果你不太明白「全新的引用」为什么是个限制,考虑下返回一个useCallback返回值:,这将会让useEffectEvent的返回值成为不变的引用,如果再去掉「只能在useEffect回调中执行」的限制,那么useEffectEvent将是加强版的useCallback。,举个例子,如果破除上述限制,那么对于下面的代码:,用useEffectEvent替代useCallback,代码如下:,相比于useCallback,他有2个优点:,那么React为什么要为useEffectEvent加上限制呢?,实际上,useEffectEvent的前身useEvent就是遵循上述实现,但是由于:,所以,useEvent并没有正式进入标准。相反,拥有更多限制的useEffectEvent反而进入了React文档[1]。,今天我们学到三个概念:,其中Effect Event在React中的具体实现是useEffectEvent。相比于他的前身useEvent,他附加了2条限制:,在我看来,Effect Event的出现完全是由于Hooks实现机制上的复杂性(必须显式指明依赖)导致的心智负担。,毕竟,同样遵循Hooks理念的Vue Composition API就没有这方面问题。,[1]React文档:https://react.dev/learn/separating-events-from-effects。
文章版权声明
1 原创文章作者:cmcc,如若转载,请注明出处: https://www.52hwl.com/29597.html
2 温馨提示:软件侵权请联系469472785#qq.com(三天内删除相关链接)资源失效请留言反馈
3 下载提示:如遇蓝奏云无法访问,请修改lanzous(把s修改成x)
4 免责声明:本站为个人博客,所有软件信息均来自网络 修改版软件,加群广告提示为修改者自留,非本站信息,注意鉴别