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

Is Redux + Effects a promising architecture for a complex Angular application?

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

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

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

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

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

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

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

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

但是像任何架构一样,有一些 cons:

  • redux 模式和解耦 UI 状态的固有优势不会自动等同于组织代码。在您的商店模型以及您的商店和组件之间的通信中,混乱很容易控制。
  • 你肯定听过很多次了:样板代码。
  • Angular 有一些 redux 风格,它们有自己的怪癖和社区。如果你的风格过时了,你就会被一个很少维护的库所困扰,或者需要做大量的工作才能将其替换掉。
  • 它将严重影响您应用的架构。因此,重要的是团队中的所有(或至少是最有主见的)开发人员都参与其中。有些人只是不喜欢它。这也很好,只要他们也提供等效或更好(和具体)的解决方案。

解耦UI状态

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

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

容器展示组件架构

虽然不是 redux 模式的一部分,但我认为 redux 模式仅在 Angular 与容器呈现模式一起使用时才可接受。您可能还看到它被称为智能-哑组件模式。它基本上是 Angular.

的 MVC

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

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

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

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

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

替代方案 - 允许每个组件与商店通信或引起其他副作用 - 是一种反模式,它将破坏解耦 UI 状态的很多好处。这也意味着您可能会从应用中的任何位置执行操作。

社区/Angular Redux 风格

人们对 redux 模式很感兴趣,不仅在 Angular 和 React 中,在原生 iOS 和 Android 中也是如此。 Angular 上有几种风格的 redux 似乎有足够的牵引力可以存在一段时间,特别是 ngrx/store.

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

就 angular 中的 redux 风格而言,一些最受欢迎的是:

  • ngrx/store
  • ngxs/store
  • 秋田

已死亡,或不再得到很好的维护:

  • angular-redux(遗憾)

UI状态为调试工具

ngrx/store(至少)提供了 Chrome Redux DevTools 扩展的使用。这是一个很好的工具,可以检查你的 redux store 以及每次调度一个动作时它是如何变化的。

样板文件

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

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

组织代码

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

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

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