对于复杂的 Angular 应用程序,Redux + Effects 是一种很有前途的架构吗?

Vin*_*com 3 redux ngrx-effects angular

对于可扩展的 Angular 应用程序,我渴望使用 redux 模式并使用效果、操作和实体。我认为它使代码更加结构化,因为您必须定义 Effect 将使用的 Actions 来触发副作用和 Store 更改。数据将结构良好,代码必须位于特定位置,这不会给您带来杂乱无章的代码的可能性。

然后,我也担心不选择可能因任何原因而终止的解决方案。

那时我想知道是否还有另一种更好的解决方案,或者至少是一个可靠的竞争对手。“更好”,我的意思是更简单(但不是更小的可扩展性),以及社区将建立的解决方案,而不是选择另一条路线。

这种架构是 Angular 中最先进的吗?

请详细说明您的答案,并在必要时与 Redux-Saga 和 Redux-Thunk 或其他解决方案进行比较。

Don*_*ghn 5

我强烈支持 Angular 应用程序中的 redux 模式,因为它具有以下优点

  • UI 状态与视图分离
  • 与容器表示组件架构配合得非常好
  • 得到社区的大力支持
  • UI 状态成为一个额外的调试工具(取决于你的 redux 风格)

当与容器表示组件架构一起使用时,redux 是可扩展应用程序的绝佳选择。

但与任何架构一样,也有一些缺点

  • Redux 模式和解耦 UI 状态的固有优势并不自动等同于有组织的代码。在您的商店模型以及您的商店和组件之间的通信中,混乱很容易占据主导地位。
  • 毫无疑问,您以前听过很多次:样板代码。
  • Angular 有几种不同风格的 redux,它们有自己的怪癖和社区。如果你的风格过时了,你就会陷入一个很少维护的库中,或者需要做很多工作来改变它。
  • 它会严重影响您的应用程序的架构。因此,重要的是团队中的所有(或至少是最固执的)开发人员都参与其中。有些人就是不喜欢它。这也很好,只要它们还提供等效或更好(和具体)的解决方案。

解耦 UI 状态

Redux 应用程序使用 astore来保存所有 UI 状态,具体取决于您的组件架构,特定或所有组件可以访问这些状态以更新视图。当然,这并不意味着您不能拥有在组件销毁时消失的内部组件 UI 状态。

以这种方式解耦(全局)UI 状态允许您以不同的方式使用它,您通常会通过使用所谓的选择器来使用它。这类似于使用数据库获取满足服务器请求所需的所有数据。

容器展示组件架构

虽然不是 redux 模式的一部分,但我认为 redux 模式只在 Angular 中与容器表示模式一起使用时才可接受。您可能还见过它称为智能哑组件模式。它基本上是 Angular 的 MVC。

容器组件:您将应用程序拆分为功能域和/或屏幕,每个功能域和/或屏幕都有一个所谓的“容器组件”。对于每个功能,这是唯一允许与 UI 状态和其他应用程序范围的依赖项(例如,路由器、ActivatedRoute)通信的组件(有一些必要的例外)。容器充当它使用的叶节点(表示组件)的控制器。

容器组件包含您的功能域/屏幕的所有业务逻辑,并协调其单独的表示组件和应用程序范围的依赖项(例如商店、路由器和服务)之间的通信。请注意,我还包括了典型的角度服务,例如路由器和激活的路由 - 很少有充分理由让纯粹的展示组件访问 URL 或查询参数。他们应该通过输入获取这些数据(这还有另一个好处是更容易进行单元测试)。

不幸的是,有时将容器嵌套在容器中会更容易。例如,在子路由中,通过路由器出口发送数据通常是不值得的。此外,通过深度嵌套组件的输入传递数据可能会变得乏味。

展示组件:所有其他组件都是展示组件(哑组件),它们对应用程序的其余部分一无所知。为了设置他们的 HTML 模板,他们通过@Inputs 获取数据。他们也不应该(直接)在他们的 HTML 模板之外造成任何副作用。例如,要更改 UI 状态,它不会直接向 store 发送操作,而是通过 @output 通知容器发生了某些事情,然后容器决定是否应发送操作。

演示组件也不会导致任何其他副作用。他们总是使用@outputs 来通知容器组件,容器组件决定如何处理这些信息。例如,您的演示文稿显示了一个超级英雄列表。当用户单击超级英雄以获取更多信息时,您的演示文稿不会打开新页面(它对页面一无所知)。相反,它通过其@output 向容器发送一个带有超级英雄 ID 的事件。然后容器可以打开一个新页面,或者打开一个弹出窗口,或者更新一个兄弟组件等等。这样你的展示组件变得更可靠、更容易测试和更可重用,同时你的 UI 状态变化和其他副作用被限制到您的容器组件。

另一种选择——允许每个组件与商店通信或引起其他副作用——是一种反模式,它将破坏解耦 UI 状态的许多好处。这也意味着您可能会在您的应用程序中的任何一点执行操作。

社区 / Angular Redux Flavors

redux 模式引起了很多人的兴趣,不仅在 Angular 和 React 中,而且在原生 iOS 和 Android 中也是如此。Angular 上有几种 redux 版本,它们似乎有足够的吸引力,可以持续一段时间,尤其是 ngrx/store。

Angular 中的 redux 概念与 React 中的略有不同。例如,redux-thunk 是一个反应库,而 angular 没有完全相同的东西(如果不正确,请注意)。在 ngrx/store 中,动作是在一个 effect 中处理的,并且使用 observables,这可能需要一些时间来适应。此外,可能需要链接多个效果才能获得与 redux-thunk 相同的结果。

至于 angular 中的 redux 口味,一些最受欢迎的是:

  • ngrx/商店
  • ngxs/商店
  • 秋田

死亡,或不再维护良好:

  • angular-redux(可悲的是)

UI 状态作为调试工具

ngrx/store(至少)提供了 Chrome Redux DevTools 扩展的使用。这是一个很好的工具,可以检查您的 redux 存储以及每次分派操作时它的变化情况。

样板

以原始形式使用 redux 时,您将编写大量样板代码。这可以通过以下几种方式减少:

  • 编写自己的工厂。例如,为操作编写一个工厂函数,该函数返回一个具有 4 个操作的对象:加载、成功、错误、重置。相应地创建 effect 和 reducer 工厂,它们都以定义的方式处理 redux 模式。
  • ngrx 有它自己的 redux 实体变体,它以类似于上面的“滚动你自己的”方法的方式减少样板代码
  • ngrx 最近合并了 ngrx/data 库,它甚至进一步抽象了 redux 中的一些东西,几乎不需要样板代码

有组织的代码

如上所述,随着应用程序的增长,您的商店很快就会变得杂乱无章。通常,我们将商店视为视图的一面镜子,并根据构建的第一个视图定义我们的商店。然后,我们最终会在存储中产生大量需要重构的重复项。

通过从每个特定视图退后一步来查看多个视图所需的 UI 状态并至少部分规范化商店,您可以依靠选择器来组成每个视图所需的 UI 状态。

与 React 中的 Redux 不同,可以通过将它们拆分为功能模块来拥有单独的存储。虽然这乍一看似乎是个好主意,但当您需要在模块之间共享状态时,它通常会导致麻烦,尤其是当您有惰性模块时。最后通常不值得麻烦,所以我建议从应用程序模块级别的一个商店开始,直到您绝对需要拆分商店。

  • 谢谢你!这个问题常常是固执己见的,因为我们忘记了上下文。商店、效果或实体都有成本,学习也是如此。明智地使用不同的技术可以节省复杂性和意大利面条式代码。我经常看到,由于代码没有组织,开发很快就变得复杂。你失去了性能、灵活性,也许还有敏捷性,最终 Ui 或 UX 又如何呢?样板代码很烦人,函数反应式编程也很复杂,但最糟糕的是你的应用程序变成了一场噩梦。Redux 减少了你的自由,但它也让你变得更强大。 (2认同)