Follow this document up along with this demo ngrx-ducks-12. There you will find the entire code that is shown in this article.💎
Implement State Mutations
First create a file where the mutation logic for a certain state slice should live. Put selectors logic here as well.
Add a class that implements the needed Case Reducers, builds required selectors and triggers actions.
createDuck supports to create both triggering actions (for Effects) and mutating actions. Second parameter of createDuck is a Case Reducer. It has a similar style of creating a reducer which actually makes state mutations.
The decorator StoreFacade introduces a new mechanism how the Facade is connected with the Store.🚀
Create Reducer automatically
If you use Ducks there is no need to maintain switch-case statements. Now you can create the Reducer based on the Ducks you have created inside the Facade class.
import { createDuck, getReducer, StoreFacade } from'@ngrx-ducks/core';@StoreFacade()exportclassCounterFacade { duck1 =createDuck('Duck 1',/* reducer function */); duck2 =createDuck('Duck 2',/* reducer function */); duck3 =createDuck('Duck 3',/* reducer function */);}// declare initial state and export counterReducerconstinitialState= { count:0 };exportconstcounterReducer=getReducer(initialState, CounterFacade);
Just created counterReducer is a variable which can be used in ngrx method combineReducersdoc. From that point our implementation of a reducer is finished. Example below shows us basic implementation.
Since the whole logic is implemented in a Facade (CounterFacade in our case) we only need to import that Facade.
🎉 The API allows you to create dynamic facades and your components do not even know that Redux is working behind the scenes. We only rely on the contracts that we use messaging and streams.
👓Thanks to TypeScript each method is strictly typed and the whole process of creating or dispatching Actions is transparent.
@Component({/* ... */})exportclassCounterComponentimplementsOnInit {/* ... */ngOnInit() {this.counter.loadCount.dispatch(5000);// ^ only type number is allowed 🎉// - dispatches action: type: '[Counter] Set initial value'// payload: 5000 }}
Use NgRx's selectors
Creating selectors is the same way as it's in NgRx.
import { bindSelectors, StoreFacade } from '@ngrx-ducks/core';
import * as selectors from './counter.selectors';
@StoreFacade()
export class CounterFacade {
select = bindSelectors(selectors);
}
What if I don't want to dispatch the action directly?
No worries, ngrx-ducks gets you covered in this question. Each dispatching method provides an Action Creator.
ngOnInit() {// Yields Actionthis.counter.loadCount(5000);// {// type: '[Counter] Set initial value',// payload: 5000// }// Dispatches an actionthis.counter.loadCount.dispatch(5000); }
You see .loadCount(5000); is a method as well. 🤯 This addition is very useful if you need to produce actions being returned by an Effect.
Effects
You may wonder if @ngrx-ducks can help you with actions being dispatched to an Effect. Short answer: Yes, it can.
Setup
Let's use createDuck again! createDuck is the only entry point you need to know to create and dispatch actions. It works with calling Effects as well. It works with Effects just like actions work with Effects in ngrx.
import { currentCount } from'./counter.selectors';@Component({/* ... */})exportclassCounterComponent { counter$:Observable<number>;constructor(private counter:CounterFacade) {// let's dispatch an action which is handled by an Effectthis.counter.loadCount.dispatch(10); }}
Inside Effects
The last question is how an Effect itself handles actions with ngrx-ducks. An Effect filters the action type first. Let NgRx do it!😁