我正在开发一个angular 1.xx项目并考虑将我的代码升级到angular 2。
现在在我的项目中,我有许多服务(工厂)用于处理数据,这些数据几乎将数据保存在js数组(缓存和存储)中,并通过使用下划线处理数组来处理这些数据。
我在angular2中发现了很多使用ngrx的例子。
与使用数据服务处理数据相比,使用商店有什么好处?
如果我有多种数据类型(库存、订单、客户...),我的应用是否需要多个商店?
如何构建(设计)我的应用程序以处理此类多种数据类型?
尽管您的问题主要是基于意见的,但我可以为您提供一些想法,为什么 ngrx 是一个不错的选择。尽管人们说将所有应用程序状态放在一个对象(单一状态树)中并不是一个好主意。但是,在我看来,无论如何,您的状态都会存在。有了一个商店,它就在一个地方,突变是明确的和跟踪的,而不是到处乱扔的,并由组件在本地维护。此外,您可以从应用程序中的商店中选择特定属性,因此您只能选择您关心的数据。如果您通过始终返回一个数组并使用 Observables 在您的 reducer 中包含不变性,则可以使用 ChangeDetectionStrategy OnPush
。OnPush
给你一个很好的性能提升。让我们看一下来自官方 Angular文档的下图:
如您所见,Angular App 是使用组件架构构建的,这导致了组件树。OnPush
on a component 意味着只有当输入属性发生变化时,才会启动更改检测。例如,如果Child B
isOnPush
和Child A
isDefault
并且您更改了内部的某些内容Child A
,Child B
则不会触发更改检测器,因为没有输入属性发生更改。但是,如果您更改内部的某些内容Child B
,Child A
将重新渲染,因为它具有默认的更改检测器。
关于性能和单一状态树的内容太多了。存储的另一个优点是您可以实际推断您的代码和状态更改。所以大多数 Angular 1.x 应用程序的现实是范围汤。这是Lukas Ruebbelke博客文章中的一张漂亮图片:
这张照片很好地证明了这一点。Tero Parviainen 的另一篇文章谈到了他如何通过禁止 Angular 应用程序来改进他的 Angular 应用程序ng-controller
。这一切都与范围汤有关,管理不断变化的状态是一件困难的事。redux
动机如下:_
如果一个模型可以更新另一个模型,那么一个视图可以更新一个模型,该模型会更新另一个模型,而这反过来可能会导致另一个视图更新。在某些时候,您不再了解应用程序中发生了什么,因为您无法控制其状态的时间、原因和方式。当系统不透明且不确定时,很难重现错误或添加新功能。
通过使用ngrx/store,您实际上可以解决这个问题,因为您将在您的应用程序中获得清晰的数据流。
由于 ngrx 受到 redux 的高度启发,我想说同样的主要原则适用:
因此,在我看来,最大的好处是您能够轻松地跟踪用户交互和状态变化的原因,因为您调度动作并且这些动作总是指向一个位置,而对于普通模型,您必须找到所有引用并查看发生了什么变化以及什么时候。
使用 ngrx/store 还可以让您使用devtools来调试您的状态容器并恢复更改。我想,时间旅行是 redux 的主要原因之一,如果你使用的是普通的旧模型,那是相当困难的。
@muetzerich 已经提到的可测试性也是使用ngrx/store 的一个好处。Reducers 是纯函数,这些函数很容易测试,因为它们接受输入并简单地返回输出,并且不依赖于函数外部的属性并且没有副作用,例如 http 调用等。
回到底线,我想说不需要使用 ngrx/store 来做这些事情,但是你会受到限制(上面提到的三个原则),它提供了一个通用的模式并带来了很好的好处.
对于您的问题:
如果我有多种数据类型(库存、订单、客户...),我的应用是否需要多个商店?
不,我不建议使用多个商店。
如何构建(设计)我的应用程序以处理此类多种数据类型?
也许 Tero Parviainen 的这篇博客文章可以帮助您弄清楚如何设计您的商店。他解释了如何为示例应用程序设计应用程序状态树。
关于使用商店的好处的一个很好的解释,你可以在文档中找到
集中的、不可变的状态
所有相关的应用程序状态都存在于一个位置。这使得追查问题变得更加容易,因为错误时的状态快照可以提供重要的洞察力,并使重新创建问题变得容易。这也使得诸如撤销/重做等众所周知的难题在 Store 应用程序的上下文中变得微不足道,并启用了强大的工具。
表现
由于状态集中在应用程序的顶部,因此数据更新可以通过依赖于存储切片的组件向下流动。Angular 2 是为了优化这种数据流安排而构建的,并且可以在组件依赖未发出新值的 Observable 的情况下禁用更改检测。在最佳商店解决方案中,这将是您的绝大多数组件。
可测试性
所有状态更新都在 reducer 中处理,它们是纯函数。纯函数测试起来非常简单,因为它只是输入,对输出进行断言。这使得测试应用程序的最关键方面成为可能,而无需使用模拟、间谍或其他会使测试变得复杂且容易出错的技巧。
多家门店?
IMO 使用一个商店并将您的数据类型作为属性添加到您的商店中。
ngrx.store 做了一个精心设计的组件/服务会做的事情,并带来额外的好处。到目前为止,我很早就开始研究它是如何结合在一起的,这就是我发现的:
服务和组件很容易造成无法维护的混乱。如果您有级联操作、复杂的数据交互和对远程位置的调用,您最终会构建一个与 ngrx 中的 action-reducer-store 安排几乎相同的服务。小的纯函数、可观察对象等。ngrx 已经有了,为什么不使用它并从它所代表的思想和模式中获益。
如果强制/鼓励对小型可测试功能进行思考。为中等复杂的组件布置一个或多个 reducer 会强制执行一项规则,该规则将消除许多耗时的陷阱。没有什么比追踪源自回调队列的准多线程竞争条件更能耗费数小时的时间了。我确信这可能发生在 reducer 上,但它简化了对调用序列和状态的访问以进行调试。
Angular2 模式变得更容易。具有显示逻辑的模板,组件作为模板所需的所有点点滴滴的聚集地。服务变得更简单,因为它们只是进行远程调用或处理来自任何地方的数据的 io。然后是用于维护和更改状态的动作和减速器,这会触发所有其他部分响应新状态。我发现使用组件/服务模式,其中任何一个都将开始变得庞大而复杂,其副作用是变得非常难以调试。我的服务最终存储状态并执行数据 io。
可观察的。rxjs.store 中的一切都是可观察的,这是响应式应用程序的基础。将应用程序状态构建为可观察的状态有时有点晦涩难懂或不是很简单,但弄清楚并做好它会在以后产生巨大的收益。
我能看到的唯一负面因素是减速器很快变得非常大。似乎有很多情况会重复使用不同名称的相同代码。我的大脑尖叫着“带参数的函数”,但它不是那样工作的。另一方面,这是应用程序的结构和状态以所有细节表达的地方,所以那里肯定有很多。当出现问题时,不可避免地会出现问题,将纯函数作为问题的根源可以更容易地追踪和修复。