NgRx鸭| 动态立面

改善开发经验



在与来自不同公司的同事交谈时,我注意到有很多团队喜欢NgRx。 在我们的讨论中,这种想法并没有离开我:


“维护更少的代码,并更多地遵循写作指南,以方便后续扩展,将是很好的


这促使我开始探索各种Redux重构技术。 我观看了视频,阅读了Redux的文章和文档。 最后,我为NgRx编写了一个名为NgRx Ducks的插件


目标


基本上,创建ngrx-ducks是为了简化使用NgRx的工作。


  1. 使用Decorator API简化了动作处理,从而减少了同时配置Reducer和动作创建者所需编写的代码量。 NgRx Ducks自动生成动作创建者和减速器功能
  2. 技术支持较少,因为您无需编写枚举或联合类型
  3. 借助直观的类型化API,您可以将其用作可注入服务 ,从而提供更清晰的应用程序逻辑,该API为您设置了与商店的交互。

如何运作?


该库是NgRx上的额外层。 它会自动为您创建动作创建者和化简功能。 此外,您还将获得可以在组件中使用的服务。 该服务提供了严格类型化的API,该API允许调度操作和从存储中选择数据。


NgRx Ducks库不会修改现有的NgRx行为。 它仅控制可观察的存储库和调度方法。



由于NgRx Ducks仅依赖于分发 ,并且存储库提供了可观察的事实,因此即使版本中有重大更改,NgRx Ducks仍与NgRx兼容。

安装方式


NgRx Ducks与现有NgRx项目无缝集成。 只需安装npm软件包,即可开始使用。


npm install @co-it/ngrx-ducks #  yarn add @co-it/ngrx-ducks 

装饰器API


NgRx Ducks的主要思想是将动作类型和更改器逻辑( 也称为reducers )结合起来。 因此,添加了@Ducksify装饰器以注释常规类。


 import { Ducksify } from '@co-it/ngrx-ducks'; @Ducksify<number>({ initialState: 0 }) export class Counter {} 

装饰器允许您指定状态的initialState 。 传递initialState可使NgRx Ducks稍后自动生成reducer函数。


现在,您可以将变异逻辑放在类中。 不再需要编写switch-case表达式 。 相反,我们使用动作装饰器在动作类型和变异逻辑之间创建映射。


 import { Action, Ducksify } from '@co-it/ngrx-ducks'; @Ducksify<number>({ /* ... */ }) export class Counter { @Action('[Counter] Increase by passed value') increaseBy(state: number, payload: number): number { return state + payload; } } 

NgRx Ducks用相应的变异逻辑映射每个动作。 Duck包含生成减速器功能的所有必要信息。


减速器功能


减速器功能是使用NgRx Ducks自动生成的。 reducerFrom工厂将创建一个查找表,以将每种操作类型映射到其对应的变异逻辑。


 import { reducerFrom, DucksifiedAction, ... } from '@co-it/ngrx-ducks'; export function reducer( state: number, action: DucksifiedAction): number { return reducerFrom(Counter)(state, action); } 

您仍然需要将reducerFrom包装在导出的函数中,以与AoT编译器一起正常工作。


必须使用NgRx将生成的reducer添加到ActionReducerMap中( 请参见下面的示例 )。


鸭威!


最有趣的还没到! NgRx鸭子的目标是简化与仓库的交互。 通过自动生成reducer功能,一切都很好,让我们看一下也在此处创建的动态外观


@Ducksify装饰器还负责将您的鸭子作为服务注册到Angular IoC容器中。 这意味着您可以将鸭子嵌入组件中!

保管箱动作分派


NgRx Ducks为Duck添加了一些修复程序,这些修复程序使您可以使用简单的函数调用而不是手动分派操作。 您可以在组件内部获得类型化的API。


 import { Duck } from '@co-it/ngrx-ducks'; @Component({ /* ... */ }) export class CounterComponent { constructor(@Inject(Counter) private _counter: Duck<Counter>) { this.counter.incrementBy(42); } } 

您实现的是Duck,而不是Counter。 Duck会自动为crementBy创建一个动作创建器,该动作创建器将使用传递的值(有效负载)来分派动作。 由于具有动态TypeScript类型,因此您可以在IDE中立即获得自动完成功能。


简而言之,NgRx Ducks使处理动作的整个过程自动化。 您只需在Duck中配置一次操作,然后再使用为您自动生成和更新的类型化动态外观。


从存储中检索数据


Duck使用NgRx选择器从存储读取数据。 每只鸭子都有一个接受选择器的助手选择。


让我们想象一下,我们的Counter是使用“ counter ”键注册为NgRx函数的。 这将允许我们进行以下选择器设置。


 import { createFeatureSelector, createSelector} from '@ngrx/store'; const visitCounter = createFeatureSelector<number>('counter'); const count = createFeatureSelector<number>(count => count); @Component({ /* ... */ }) export class CounterComponent { count$: Observable<number>;constructor(@Inject(Counter) private _counter: Duck<Counter>) { this.count$ = this.counter.pick(count); this.counter.incrementBy(42); } } 

您可以在stackblitz.io上观看演示。


Duck允许触发状态突变和从存储库查询数据。 您只需要一个“已利用”服务,该服务就可以设置一个方便的API与存储进行交互。


最后


NgRx Ducks还可以与Effects无缝集成! 但是我们将仅在下一篇文章中对此进行详细分析。


如果您希望现在就找到它,可以参考复杂的示例,该示例也可以在stackblitz.io中找到。


TL; DR


  • NgRx鸭子作为NgRx之上的额外层。
  • 您可以轻松地将NgRx Ducks集成到现有项目中。

  • ... 自动生成动作创建者和化简函数
    。...使动作枚举器和联合类型不必要
    ... 它是一个动态外观,可以嵌入到组件中
    。...提供动态类型的自调度;抱歉的操作
    ... 允许使用pick-API从存储中读取数据
    。...可以由Effects使用(请参见Demo )。

伙计们!


希望我能说服您尝试NgRx Ducks 。 另外,我想知道您对这个库的看法。 如果您有任何想法,只需在GitHub上编写

Source: https://habr.com/ru/post/zh-CN485080/


All Articles