在 angular 2 中使用商店 (ngrx) 有什么好处

What are benefits of using store (ngrx) in angular 2

我正在做一个 angular 1.x.x 项目并考虑将我的代码升级到 angular 2

现在在我的项目中,我有许多用于处理数据的服务(工厂),这些数据几乎将数据保存在 js 数组(缓存和存储)中,并通过使用下划线来处理这些数据处理数组。

我发现 angular2 中有许多使用 ngrx 的示例。

使用store compare与使用数据服务处理数据有什么好处?

如果我有多种数据类型(库存、订单、客户...),我的应用是否需要多个商店?

我如何构造(设计)我的应用程序来处理像这样的多种数据类型?

关于使用商店的好处的很好解释,您可以在其中找到 documentation

中心化、不可变状态

所有相关的应用程序状态都存在于一个位置。这使得跟踪问题变得更加容易,因为错误时的状态快照可以提供重要的洞察力并使问题重现变得容易。这也使得众所周知的难题(例如 undo/redo 在商店应用程序的上下文中变得微不足道,并启用了强大的工具。

性能

由于状态集中在您的应用程序的顶部,因此数据更新可以依赖于存储切片向下流经您的组件。 Angular 2 旨在优化这种数据流安排,并且可以在组件依赖于未发出新值的 Observable 的情况下禁用更改检测。在最佳商店解决方案中,这将是您的绝大部分组件。

可测试性

所有状态更新都在 reducer 中处理,它们是纯函数。纯函数测试起来非常简单,因为它只是输入,针对输出进行断言。这使您能够测试应用程序的最关键方面,而无需模拟、间谍或其他可能使测试既复杂又容易出错的技巧。

多家商店?

IMO 使用一个存储并将您的数据类型作为属性添加到您的存储中。

尽管您的问题主要是基于意见,但我可以给您一些想法,说明为什么 ngrx 是一个不错的选择。尽管有人说将所有应用程序状态都放在一个对象(单一状态树)中并不是一个好主意。但是,在我看来,无论如何,您的状态都会存在。对于 store,它只是一个地方,并且突变是明确的和跟踪的,而不是散落在各处并由组件在本地维护的。此外,您 select 应用程序中商店的特定属性,因此您只能 select 您关心的数据。如果你随后通过总是 return 数组并使用 Observables 来在你的 reducer 中拥抱不可变性,你可以使用 ChangeDetectionStrategy OnPushOnPush 给你一个很好的性能提升。看看下面这张摘自官方的图Angular docs:

如您所见,Angular 应用程序是使用组件架构构建的,这会产生组件树。组件上的 OnPush 意味着只有当输入属性发生变化时,变化检测才会启动。例如,如果 Child BOnPush 并且 Child ADefault 并且您在 Child A 中更改某些内容,Child B 的更改检测器不会被触发,因为没有输入属性发生更改。但是,如果您在 Child B 中更改某些内容,Child A 将重新呈现,因为它具有默认的更改检测器。

性能和单一状态树就这么多了。商店的另一个优势是您实际上可以推断您的代码和状态更改。所以大多数 Angular 1.x 应用程序的现实是 scope soup。这是来自 Lukas Ruebbelke blog post 的精美图片:

图片展示得很好。另一个article from Tero Parviainen talks about how he improved his Angular apps by banning ng-controller. That all relates to the scope soup and managing ever-changing state is a difficult. The redux motivation says the following see here:

If a model can update another model, then a view can update a model, which updates another model, and this, in turn, might cause another view to update. At some point, you no longer understand what happens in your app as you have lost control over the when, why, and how of its state. When a system is opaque and non-deterministic, it’s hard to reproduce bugs or add new features.

通过使用 ngrx/store 您实际上可以解决这个问题,因为您将在您的应用程序中获得清晰的数据流。

由于 ngrx 深受 redux 的启发,我想说 main principles 同样适​​用:

  • 单一事实来源
  • 状态为只读
  • 使用纯函数进行更改

因此,在我看来,最大的好处是您能够轻松跟踪用户交互和状态更改的原因,因为您发送操作并且这些操作总是指向一个位置,而对于普通模型,您必须找到所有参考和看看什么时候发生什么变化。

使用 ngrx/store 还可以让您使用 devtools 查看调试您的状态容器并还原更改。我猜,时间旅行是 redux 的主要原因之一,如果你使用的是普通的旧模型,那将是相当困难的。

@muetzerich 已经提到的可测试性也是使用 ngrx/store 的一个好处。 Reducers 是纯函数,这些函数很容易测试,因为它们接受输入并简单地 return 输出并且不依赖于函数外部的属性并且没有副作用,例如http 调用等

要跳到底线,我会说不需要使用 ngrx/store 来做任何这些事情,但是你会被限制(上面提到的三个原则)提供一个共同的模式并带来很好的好处。

针对您的问题:

如果我有多种数据类型(库存、订单、客户...),我的应用是否需要多个商店?

不,我不建议使用多个商店。

我如何构建(设计)我的应用程序来处理像这样的多种数据类型?

也许 Tero Parviainen 的这篇 blog post 可以帮助您弄清楚如何设计您的商店。他解释了如何为示例应用程序设计应用程序状态树。

ngrx.store 的功能和精心设计的 component/service 的功能一样,而且还有额外的好处。到目前为止,我还在早期研究如何将它们组合在一起,这就是我发现的:

服务和组件很容易出现无法维护的混乱局面。如果您有级联操作、复杂的数据交互和对远程位置的调用,您最终构建的服务几乎与 ngrx 中的操作-缩减器-存储安排相同。小型纯函数、可观察值等。ngrx 已经有了,为什么不使用它并从它所代表的思想和模式中获益。

If forces/encourages 思考小的可测试函数。为一个中等复杂的组件布置一个或多个 reducer 会强制执行一个规则,该规则将消除许多耗时的陷阱。没有什么比追踪源自回调队列的准多线程竞争条件更耗时的了。我确信这会发生在 reducer 上,但它简化了对调用序列和状态的访问以进行调试。

A​​ngular2 模式变得更容易。具有显示逻辑的模板,组件作为模板所需的所有点点滴滴的聚集地。服务变得更简单,因为它们只需进行远程调用或处理来自任何地方的数据的 io。然后是用于维护和更改状态的动作和缩减器,这会触发所有其他部分响应新状态。我发现使用 component/service 模式中的任何一个都会开始变得庞大和复杂,其副作用是变得极难调试。我的服务最终会存储状态并执行数据 io。

观察值。 rxjs.store 中的一切都是可观察的,这是响应式应用程序的基础。将应用程序状态构建为可观察对象有时有点神秘或不是很简单,但弄清楚并做好它会在未来获得巨大的回报。

我能看到的唯一缺点是减速器很快变得非常大。似乎有很多情况会重复使用不同名称的相同代码。我的大脑尖叫起来 'function with parameters',但它不是那样工作的。另一方面,这是应用程序的结构和状态以所有细节表达的地方,因此那里肯定有很多。当出现问题时(这是不可避免的),将纯函数作为问题的根源可以更容易地追踪和修复。