改善开发经验

在与来自不同公司的同事交谈时,我注意到有很多团队喜欢NgRx。 在我们的讨论中,这种想法并没有离开我:
“维护更少的代码,并更多地遵循写作指南,以方便后续扩展,将是很好的 。 ”
这促使我开始探索各种Redux重构技术。 我观看了视频,阅读了Redux的文章和文档。 最后,我为NgRx编写了一个名为NgRx Ducks的插件
目标
基本上,创建ngrx-ducks是为了简化使用NgRx的工作。
- 使用Decorator API简化了动作处理,从而减少了同时配置Reducer和动作创建者所需编写的代码量。 NgRx Ducks自动生成动作创建者和减速器功能 。
- 技术支持较少,因为您无需编写枚举或联合类型 。
- 借助直观的类型化API,您可以将其用作可注入服务 ,从而提供更清晰的应用程序逻辑,该API为您设置了与商店的交互。
如何运作?
该库是NgRx上的额外层。 它会自动为您创建动作创建者和化简功能。 此外,您还将获得可以在组件中使用的服务。 该服务提供了严格类型化的API,该API允许调度操作和从存储中选择数据。
NgRx Ducks库不会修改现有的NgRx行为。 它仅控制可观察的存储库和调度方法。

由于NgRx Ducks仅依赖于分发 ,并且存储库提供了可观察的事实,因此即使版本中有重大更改,NgRx Ducks仍与NgRx兼容。
安装方式
NgRx Ducks与现有NgRx项目无缝集成。 只需安装npm软件包,即可开始使用。
npm install @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上编写