NgRx Utils
This is a library provide cli tools, util functions, decorators to help reduce boilerplate and speedup your devs when working with ngrx using class based Action approach.
Inspired from ngrx-actions by @amcdnl
After version 1.2.0, We have decided to move codebase to monorepo for a bigger project, with full features cli, and support more store util functions, operators...
You can track the work of new project at https://github.com/ngrx-utils/ngrx-utils
What in the box?
-
ofAction pipeable operator. It will accept class based actions as parameters. Why this is better than ofType, default operator from @ngrx/effects? . Although ngrx/schematics and ngrx/codegen will give you tools to automatically generate some boilerplate and scaffolding enum action, reducer... for your app, it will also add a fairly large amount lines of code into your codebase. Using const or enum to store action type like this:
- When using ngrx/effect, You will have to cast type to have the correct action type because ofType only accept string. This seems acceptable, but sometimes your code look awful when there are 3 or 4 actions with same effects:
getCoilItems$ = this.actions$.ofTypeAccActionType.GetAccItems,AccActionType.RefreshAccItems,EnvActionType.GetEnvItems,EnvActionType.RefreshEnvItems,- According to ngrx/codegen proposal, to have a nice type inference in your effect ofType and get rid of this type casting, ngrx/codegen will use interface base Action, and generate a lookup type, which is another enum includes all action type value:
/*...*/;;We really feel this is like duplicating your action type enum :(
- And with all of this, you will have very nice type inference and safe type checking but the trade off is when your app scale up, a huge amount of boilerplate will be generated too. Thanks to
ofAction
pipeable operator, You now can get rid of all those boilerplate and type inference is "just work". Since ngrx-utils 1.2.0, ofAction operator will smartly infer all Action type and you won't have to use type cast anymore.
- How about reducer? Do I have to type string manually in switch block? Don't worry about it. Thanks to smart infer type of typescript and nice auto completion feature, we now can have auto complete action type without an enum or const. If you are using VSCode, add this config to your settings to show suggestions within string quote:
"editor.quickSuggestions":
Then when you type case ''
, and trigger quick suggestion shortcut Ctrl + Space
.
- Since version 1.1.0, ngrx-utils come with an builtin ngrx command to generate all boilerplate for you. All you have to do is just create Action Class declaration file like this:
user.action.ts:
;
- Then use ngrx command to generate Union Type for you. Since version 1.2.0, we have added support optionally generate reducer function with
-r
option.
# npx ngrx [g | generate] [a | action] [-r | --reducer] path/to/action npx ngrx g a -r path/to/user.action.ts
- This will generate
user.action.generated.ts
in the same folder withuser.action.ts
; ; // with -r option
This command actually is a modified version of @ngrx/codegen to accept class base action.
@Select
decorator. This is always in the wish list of developers in the first days of ngrx. No morethis.prop = this.store.select(/* some prop */)
in your Component, now you can use@Select
decorator instead as describe below).
Note: The Select decorator has a limitation is it lack of type checking due to TypeScript#4881.
Getting Started
Install
npm i ngrx-utils -S# or yarn add ngrx-utils
Then in your app.module.ts (Only Add this code to your AppModule), connect ngrx-utils to your store:
;;
And you can start using it in any component. It also works with feature stores too. You don't have to do anything in your feature module. Don't forget to invoke the connect
function when you are writing tests.
Selects
@Select
decorator has the same API with store.select method, with 1 more feature is it accepts a (deep) path string. This looks like:
ofAction:
- You can use ofAction operator instead of ofType to filter your Action type in Effect:
;;;;; ; ;
- Migrate from 1.1
before:
getUser$ = this.actions$.pipe ofActionGetUser, RefreshUser, /* cast action type when there are multi actions */ switchMapthis.myService .getAllaction.payload .pipemapnew GetUserSuccessres, catchErrorofnew GetUserFailerr ;
after: remove the type casting
getUser$ = this.actions$.pipe ofActionGetUser, RefreshUser, switchMapaction /* action will have type GetUser | RefreshUser */ this.myService .getAllaction.payload .pipemapnew GetUserSuccessres, catchErrorofnew GetUserFailerr ;
What's different with ngrx-actions?
- Only provide
@Select
andofAction
pipeable operator. We really feel that@Store
,createReducer
and@Action
from ngrx-actions increase much more boilerplate when using it in our app. - No need reflect-metadata as a dependency
See changelog for latest changes.
Common Questions
- Will this work with normal Redux? While its designed for Angular and NGRX it would work perfectly fine for normal Redux. If that gets requested, I'll be happy to add better support too.
- Do I have to rewrite my entire app to use this? No, you can use this in combination with the traditional switch statements or whatever you are currently doing.
- Does it support AoT? Yes but see above example for details on implementation.
- Does this work with NGRX Dev Tools? Yes, it does.
- How does it work with testing? Everything should work the same way but don't forget if you use the selector tool to include that in your test runner though.
Community
- Origin post from @amcdnl, exclude
@Store
,createReducer
and@Action
Reducing Boilerplate with NGRX-ACTIONS