为什么Action是Redux Action的坏名字

首先,有一点背景知识。 我认为自己是一名全栈开发人员,并且多年来一直在处理单页应用程序。 从怪异的Alpha时代开始,我就开始研究React水。 我学到了所有的钩子,被炒作了,但由于无法编写一个足够复杂的应用程序以保证需要一个状态管理器而高兴地失败了。 然后是Redux 时间:当它很快解决了整个流量架构辩论时,我了解了它的所有概念,被炒作了,然后高兴地失败了,无法对一个闪亮的新项目实施适当的状态管理。

快进到今天,以后再进行一些大型项目,我想我发现在日常生活中正确实施这些技术的失败少了一些。 在业余时间,我也一直在学习和学习榆木 ,这得益于我每天工作的一些很棒的人( 是的,如果您认为可能是您,那可能就是您 )。 经过反思,我认为这两个事实并不无关,这使我思考从Elm方面学到的概念,这些概念改善了React / Redux工作流程。

首先想到的是,对一个动作应该传达什么样的信息的理解会影响您查看和建模商店的方式 。 它是整个体系结构的核心语义部分,在学习这种状态管理体系结构时,我认为我们没有给予足够的重视。 至少我们不鼓励这样做。

简介很长,所以让我们总结一下。 也许我是唯一一个很难正确设置商店建模的人,这很好。 这种困难加上我在榆树中的经历,使我思考了对抽象概念的理解如何影响我对当前影响我的生活的技术的决定。 我在这篇文章中的重点是我目前归因于Redux Actions的语义,以及我认为该概念的名称如何使我们远离它们应具有的实际含义。

序幕

我一直对两种模式感到不快,这两种模式在我的JavaScript社区中非常常见:概念,抽象和语义通常仅次于可用性,实用性和语法。 电池通常不包含在我们的日常包装中,这导致包装所有者不关心其包装如何适应世界。

我认为, Redux在这两个方面都是一个特别的罪犯。 我最近写了一篇关于Redux的缺点的文章,其中我描绘了一幅图画,说明缺乏意见和沟通会如何损害原本具有革命性的图书馆在现实世界中的应用。 该文档在向您展示如何使用该库方面非常了不起,而在指导您如何查看和考虑您的软件方面则令人惊叹。

我在上一篇文章中指出的问题之一就是Redux Actions所具有的模糊语义。 我用业余时间编写Elm的代码越多,并将其概念运用于现实生活中的Redux代码中,就越容易理解Elm正确。 此外,我不认为这是“他们不同,但每个人都有所不同”的情况,至少在这个问题上没有。 我看到的是,拥有更多Elm经验的人有更好的时间为其商店建模,而直接去Redux的人则有更多混乱的时间(这是每个人)。

因此,让我们尝试弥合这一差距,对吧?

什么是动作?

我们都习惯了吧? 到目前为止,这是一个普通的对象。 它具有必需的类型键,可以告诉我们它代表哪种事件和数据。 让我们看看Redux在其文档中所说的话。

操作是信息的有效负载,可将数据从应用程序发送到商店。 它们是商店的唯一信息来源。 您可以使用store.dispatch()将它们发送到商店。

我会说很简单。 从这句话中,我们得到了它的语义:这是应用程序和您的商店之间唯一且唯一的通信形式。 您甚至已经知道如何调度它们! 我希望这些语义就足够了,因为这就是您从此页面获得的全部内容。

因此,让我们一起考虑。 我想编写一个简单的表格,使我可以在某些破坏性的Web平台上更改电子邮件。 我们需要一个文本输入和一个提交按钮,每个按钮都有一个动作。 我们应将动作命名为什么? SET_EMAIL_TEXTSUBMIT_EMAIL_FORM怎么SUBMIT_EMAIL_FORM ? 甚至CHANGE_EMAIL_TEXTSAVE_EMAIL ? 或者也许是REQUETS_EMAIL_CHANGE

所有这些选项都可以正常工作,我之前已经写了所有这些选项,而它们全都错了。 他们的共同点是我们的集体早期教育训练了我们必须利用的命令式思维,这与Redux提出的体系结构不太匹配。

交流,但需要什么样的信息?

我们了解到,在Redux的正确指导下,动作是与应用程序通信的一部分。 这表明行动是一种交流方式,非常有意义。

留给用户练习的后续问题是:什么样的信息? 我的应用程序应该告诉我的商店什么?

以我的经验,这个问题有两个主流答案。 大多数项目显示了两者的混合:意图交流和事件交流。 一个要比另一个更普遍,在接下来的几节中,我将让您猜测是哪个。

动作传达意图

最明显的是,一个动作将一个意图传达给Store ,该意图又将利用附加的有效负载及其内部状态来执行它。 按照这种思维方式,您的大多数操作类型都将包含命令式的动词,并且您的操作日志将看起来像是商店的一系列订单。

这种思维方式非常普遍,这也就不足为奇了。 它非常适合我们的命令式思维,并且从程序员的角度来说是正确的:如果我尝试更改某些内容,则对于我的商店来说,识别CHANGE操作是很有意义的。 还是呢?

从这个角度来看,我们留下的动作语义非常接近于普通函数的语义,对吗? 这是执行某些意图的代码块。 更进一步,这使我们感觉良好,因为在ReactRedux恳求声明性时,这些动作使我们能够进行必要的思考。 那就是事情开始错位的地方。

如果我们将动作和功能视为紧密的概念,那么我们开始分享一些不适合Redux架构的特征。 最重要和最有害的是,要使功能重复使用,而操作应根据具体情况而定。 按照这种思路,我们倾向于尝试使我们的操作可重用,因此当我需要在密码更改表单中更改用户的电子邮件时,可能已经派上用场了, REQUEST_EMAIL_CHANGE已在密码更改表单上使用过。注册。 我在两个地方而不是一个地方使用它!

问题是,这对架构有害。 为了在两个地方使用相同的动作,您需要内置一些逻辑。在我的示例中,您必须将动作关联到click以及用户注册管道。 这部分逻辑将在存储区之外,这表明已关闭某些设备。 此外,它可以在商店内部,在另外一个中间件的帮助下(可能以无害的循环运行后续商店周期,甚至发信号地为您做一些工作),但随后您会重新隐藏问题。

我通常剩下的是无数的反模式,范围从商店外的逻辑到一个用户动作调度一个以上的动作,再经过一个动作调度另一个动作而在它们之间没有真正的副作用。 我只是在这里命名,但我可能会写另一篇文章,以消除我在许多Redux项目中看到的这些气味。

好吧,我们已经深入兔子洞了。 我有点担心这与我之间的相关性,我希望同样的情况对您不适用,但是如果您这样做,您可能会感到奇怪:那么正确的沟通将是什么?

动作传达事件

是的,我可以想象您的面孔在读这篇文章,因为这是我们在谈论赶时髦的人到来之前用jQuery探索成功之道的意思。 问题是,jQuery的问题不在于事件,而在于当务之急。 当我们迁移到Redux并带来想法时,我们只是在使用更复杂的工具来解决问题,同时避免了真正的危险:我们内部的黑暗。 因此,当我尝试描绘为什么这种类型的交流更好时,请给我一些惊喜和耐心。

这种语义与普通函数的语义略有不同:它是它们的更具体的视图。 每个减少都是一个处理程序,该处理程序知道当外部世界发生某些事情时该怎么办。 这种思维方式在商店和应用程序之间翻转了责任箭头: 应用程序应将发生的情况告知商店,而商店将知道要做什么 ,而不是由应用程序通知商店要做什么。

这种区别听起来可能很愚蠢,但实际上并非如此:您不会再调用Action SETREQUESTCHANGE ,因为这些名称显然传达了意图。 该应用程序应该只是让商店知道,所以INPUT_CHANGEDBUTTON_CLICKED更像它。 您的操作日志将看起来像一系列交互,这更像是架构的内容。 拥有商店的全部目的是它将成为您应用程序的心脏和灵魂,并且将知道如何准确地处理应用程序支持的交互次数。

USER_SIGNED_UPCHANGE_EMAIL_FORM_SUBMITTED都保存用户电子邮件这一事实只是业务逻辑上的巧合,可以肯定地将其抽象为一个函数以避免重复,但这并不意味着他们应该执行一个操作。 您将不再倾向于(或至少不会如此)从单个交互中分派两个Action ,因为它不再有意义。 单个交互(例如单击,超时或服务器响应)是单个操作,因为该操作表示整个交互,而不是其意图。 最后,从减少另一个动作中分派一个动作似乎很奇怪,就像这意味着商店向自己发信号,这违反了“ 动作是与外界沟通的手段 ”的前提。

考虑交流事件的一种方式的动作会使您从命令式动词转到过去式动词。 思维方式的改变将使您的商店模型与声明性思想模型更好地保持一致,这反过来又将更适合ReactRedux架构。

那么,动作名称有什么问题?

我提出了两种方法来查看和了解正在分发的动作 。 每种方式使我们对目标的看法不同,从而导致在对复杂的前沿软件进行建模时需要解决的问题也不同。 我显然比其他人更偏爱我,现在我想稍微反思一下我们肩膀上的一个小恶魔,称为认知缓解。

作为人类,我们在所谓的理性思想中有很多偏见。 其中之一是,我们经常将容易且可识别的事情误认为正确和适当。 这只是形容词的一个小错位,它帮助我们过滤了来自周围世界的大量信息而没有太多压力,但是这使使我们紧张的事情感到不对劲。 我们也非常需要来自此信息的一致性,因此,我们将尽可能连接每个点,同时丢弃那些不利于我们在处理外部图像时不可避免要形成的简单图像的点。

对于大多数人来说,学习React尤其是Redux架构非常困难,这主要是因为它们背离了对世界的舒适需求。 他们要求您不要下达命令,而要描述您想要从每个世界状态中获得什么。 他们敦促您不要执行副作用,并尝试以一种比以往更奇怪的方式来管理您的复杂性。 在这样的环境中,认知轻松会成为我们做出决策的更大动力,因为没有别的感觉是对的,而这正是我认为Action名称具有创意的地方。

由于感觉正确,我们最终滑向了通知意图的命令行动。 这种心态与命令式编程非常吻合,因为我们从一开始就很珍惜(并且有充分的理由)。 感觉很熟悉,因为我们已经不在习惯的地方了,至少我们可以订购商店,就像我们过去为我们工作的那样。 最后,它与“ 动作 ”名称完全吻合,它表示交流应该做某事,应该施加改变,应该行动。

问题是,至少在我看来,我们导致错误的语义,不仅是因为为概念选择的名称,而且由于各种原因,导致我们倾向于首先学习使用非功能性语言进行编码。 这种语义上的漂移导致人们对Redux提出的惊人架构的理解更糟(或至少更加困难)。 图书馆和社区不费吹灰之力地指导我们通过这种概念上的理解,并始终将实用性放在第一位,这在我看来是可耻的,因为它使许多(首先应该被)这些概念所吸引的开发人员远离了其他领域语法。

这不是行动,而是一种反应 。 它不是在发出命令,而是在描述行为。 这不是强制性的,而是声明性的。 这就是为什么Action是Redux Action的坏名字的原因

结语

所以我想从这篇文章中得到什么? 我想就我的日常生活中一个非常重要的图书馆方面提出自己的观点,但是如果我们说实话,我也想抱怨一点。 我认为,作为一个社区,我们可以做得更好,以使我们的概念井井有条,更好地定义和命名它们,并尽力而为地教导它们,甚至只是在彼此之间。

不尝试回答所有问题是件好事,因此要信任您的用户,这是有好处的,但是在某些情况下,不受质疑只能意味着让问题由社区集体认知缓解甚至一个孤独的开发人员来解决,以解决架构问题。老实说对新手来说太激进了。

对于Redux所采用的概念,我认为Message是比Action更好的名称,但这并不是重点。 关键是人类的理解是脆弱的,并且可以被最小的细节所影响,所以我们可能想先将我们的理解集中在基础概念上,然后如何将其应用于我们的创业公司。

嘿,也许我弄错了。 也许语义上有所不同是有原因的,我而不是Redux遗漏了这里的要点。 但是然后您需要告诉我,请这样做!