在 Angular 中创建适应性强的数据存储
在 Angular 中创建适应性强的数据存储
原文:https://medium.com/hackernoon/creating-adaptable-data-stores-in-angular-38df2d22b5c
应用程序开发过程中最有趣的问题之一是管理状态。新的范例已经改变了 web 应用程序处理和操作其状态的方式,从 AngularJS 的双向数据绑定机制转向具有 React 和 Redux 的更具功能性的单向流。现在 Angular 已经过时一段时间了,并且接近“稳定”,同样的问题出现在如何最好地管理应用程序状态上。通过@Input绑定和@Output事件发送和操作数据对于小型应用程序来说非常有效,但是随着应用程序的增长,这种方式很快就变得不实用了。
对于那些希望在没有第三方依赖的情况下工作的人,Angular 提供了一些工具来解决大多数状态管理问题:
@Input和@Output:通过连接事件发射器和组件级绑定,在组件链中传递状态- 提供者/服务:通过依赖注入仔细管理数据
在本文中,我将讨论一种状态管理的服务方法模式,我发现当应用程序需要比组件绑定更大的灵活性时,这种模式特别有用。
@输入和@输出
所有 Angular 开发人员都熟悉这些@Input和@Output关键字,因为它们提供了管理状态的最直接(通常也是最常用的)方法。通过仔细构建组件,共享状态存在于父组件中,父组件将该状态传播给许多子组件,这一过程在视觉上类似于一棵树。任何时候孩子想要更新父母的状态,他们必须通过一个@Output绑定来完成。这为整个父子关系中共享的状态提供了明确的分离。
@Input组件层次结构非常适合小型应用程序或独立的组件组。然而,当扩展一个应用程序时,这种模型会出现问题。当引入的新组件在组件层次结构中远离原始数据源时,与这些组件进行通信会变得很困难。在这些情况下,服务被用来在组件之间传送数据。
尽管该服务是解决这个问题的一个很好的解决方案,但它通常实现得很差。因为包含在这些服务中的数据通常是可变的(大多数应用程序将它们的状态建模在数组或对象中),所以所述服务的消费者必须小心他们如何利用它,以免他们产生副作用。此外,具有太多逻辑的服务可能很难维护,因为它们的功能经常在应用程序的许多地方使用。
服务数据管理
在处理大型应用程序时,我们希望避免包含过多逻辑和大量可变数据的服务。因此,我提出了一种简单的方法,用“数据存储”形式的服务来处理状态管理。
数据存储背后的想法有三点:
- 将一段数据隔离到一个服务中,以便它可以在整个应用程序中共享
- 缓和数据的所有变化,以便可以容易地跟踪变化
- 限制状态可以改变的程度,以防止不必要的副作用。
想象一下,我们有一个应用程序,它将包含足够复杂的数据,以至于我们不能仅仅依靠@Input和@Output绑定。在这个应用程序中,我们希望通过调用我们的数据存储并在整个应用程序中更改数据来切换按钮标题的颜色。也许我们有许多不同的面板、文章和页面提供这种切换功能,它们都位于应用程序的不同区域。
我描述的组件如下所示:
尽管这个组件相当简单,但是数据存储的核心原则仍然适用。在组件中,我们通过 Angular 的内置 DI 传递数据存储,并使用下面的代码:constructor(private appState: AppState) {},这样我们就可以访问组件中的应用程序状态。在ngOnInit()生命周期函数中,我们订阅应用程序的状态(在这种情况下,是一个布尔值),它将在每次存储发生变化时为我们提供全新的状态。为了切换文本的颜色,我们采用了一种通过商店本身来操纵商店数据的方法this.appState.toggleRed()。
由于订阅,商店包含最新的应用程序数据。每当数据发生变化时,商店的所有订户(例如,该组件)都将自动更新。在私有的 BehaviorSubject 的帮助下,任何想要改变存储状态的组件都必须通过存储本身来完成,确保没有人能够以破坏应用程序的方式操纵数据。
下面是示例应用程序中的数据存储服务:
在上面的代码中有三种主要的技术。首先,我们应用程序中的实际数据对于数据存储来说是私有的,任何消费组件都无法更改。行private _isRed = new BehaviorSubject<boolean>(false);用 RxJS 的 BehaviorSubject 初始化这个私有数据,用来表示一个可以随时间变化的值。BehaviorSubject 比常规 Subject 用得多,因为它可以被提供一个初始值,在本例中是false。
第二,商店内的数据通过 RxJS 可观察的公开,允许消费者接收最新的数据,而不能够直接修改它(通过订阅)。因为一个可观察的事物不能被直接改变,所以我们商店里的数据是安全和隔离的。
最后,为了允许消费者更改数据存储中的数据,提供了一个 API,它将强制所有更改都通过存储本身。这样就不需要跟踪与该数据交互的所有组件,以便跟踪对其所做的更改。例如,当我们的示例应用程序中的组件希望改变其文本的颜色时,它必须通过调用数据存储中可用的toggleRed方法来实现。只有这样,数据存储才会决定如何更新其数据。
结论
数据存储服务模型需要一点额外的代码来运行,但是与简单地将数据直接存储在服务的属性上相比,它提供了许多优势。不仅数据被隔离到单一来源,而且通过后台 API 管理更改和更新也更容易。通过在应用程序中利用许多这样的存储来存储孤立的数据组(想想:PhoneNumberStore、EmailStore、LoginStore等)。)管理大型应用程序的复杂性变得容易多了。
虽然上面我没有提到,但是也有无数的第三方库为状态管理的问题提供了不同的解决方案。我个人最喜欢的是 ngrx ,这是一个提供了大量 Redux 启发的应用程序管理方法的库。这些库需要额外的配置和预先学习,但是对于具有复杂数据需求的应用程序来说,它们是非常有用的。
资源
这里有一个交互源代码的链接。