NgRx is inspired by the Redux pattern.
NgRx stores a single state and uses actions to express state changes.
NGRX state management lifecycle
I installed the Angular command line interface using npm
% npm i -g @angular/cli
I created a new Angular project using "ng new"
% ng new haddley-ngrx
ng new haddley-ngrx
The state of the haddley-ngrx application is a number between 1 and 6.
The app component template displays the "value"
The app component class sets the "value"
The app component style ensures the value is big enough to see at a distance
A random number between 1 and 6.
Every time a user refreshes the haddley-ngrx app a random number is displayed.
I updated the code so that the number is updated in response to a mouse click.
I added (click)="updateValue()" to app component template
I added code to update "this.value" to app component class
I refactored the code
I created a "valueBetween1And6" function
I updated the declaration of value to use the "valueBetween1And6" function
I ran "ng test" to check that the haddley-ngrx application was working properly.
Two tests passed and one test failed.
ng test
karma page
'haddley-ngrx app is running'?
In this case the haddley-ngrx app is working fine and the test is wrong.
I want the application to display a value between 1 and 6.
I don't want the application to display 'haddley-ngrx app is running'.
So I updated the last test.
app component should render a number between 1 and 6
ng test
Using NGRX I moved "value" out of the app component and into a store.
I updated the app component to dispatch an Action in response to the (click) and to refresh the page content in response to a store Selector.
I created a src/app/state folder and a src/app/state/dice folder.
I created a dice actions typescript file and defined three actions: {roll, rollSuccess, and rollFailure}
The app component will dispatch a "roll" Action in response to a (click).
The app component will not dispatch the rollSuccess Action or the rollFailure Action.
npm i @ngrx/store
I created a dice state typescript file and defined a DiceState interface.
NGRX should not throw an exception in response to the app component dispatching an Action.
Instead a Selector will return a result (to the component) indicating success or failure.
For completeness I have included a (nullable) error value in the DiceState interface.
DiceState interface
I created a dice reducer typescript file to specify how Actions will be processed.
The rollSuccess action updates the state.value to the number passed to it as a property.
The rollFailure action updates the state.error to the text passed to it as a property.
It might seem odd that the roll Action updates the state.error but does not update the state.value (see Effects below).
diceReducer
As my application grows it is likely that I will add features that are unrelated to dice.state.
With that in mind I have created an app.state interface that can be used in the future to access dice.state and state related to other features.
I added an app.state typescript file to the state folder.
app.state interface
The app.component will access the dice state using selectors.
I added the dice.selectors typescript file and created the two selectors the app.component needs.
dice.selectors
To get NGRX to work I needed to add two modules to the app.module file.
First I added StoreModule
adding StoreModule to app.module
I updated app component template and app component class to make use of the selectDiceValue and selectDiceError selectors.
app component class
app component template
ng serve -o
(click) seems to do nothing
refreshing the page seems to work
After these updates the tests fail.
No provider for Store!
To get the ng tests to pass we need to add a "mock store"
provideMockStore
ng test success
When the app component dispatches the "roll" Action the app component does not provide a value.
Without additional effort the roll Action is not in a position to update the state.
NGRX effects address this problem.
I created a DiceEffects class that responds to "roll" Actions.
When the DiceEffects class spots/notices/is notified of a roll Action it calculates a random value between 1 and 6 and then (some moments later) dispatches a corresponding rollSuccess or rollFailure Action.
dice.effects
EffectsModule import added to AppModule
The final result is an Angular application that uses NGRX for state management.
ng test
ng serve -o