NGRX Tutorial Series
NGRX Tutorial Series
5-Part Series
Page 1 of 37
Table of Contents
1. Cover
3. Introduction
Page 2 of 37
NgRx Code Review Checklist
You've downloaded our NgRx tutorial
series, a great first step to ensuring that
your getting the most out of NgRx. The
second step? Download our free NgRx
code review checklist. A helpful
resource to help you successfully
review your NgRx code.
DOWNLOAD NOW
SIGN UP TODAY
Page 3 of 37
Introduction
About Intertech
Founded in 1991, Intertech delivers technology training and software
development consulting to Fortune 500, Government and Leading Technology
institutions.
Learn more about us. Whether you are a developer interested in working for a
company that invests in its employees or a company looking to partner with a
team of technology leaders who provide solutions, mentor staff and add true
business value, we’d like to meet you.
www.intertech.com
Page 4 of 37
Chapter 1: Quickly Adding NgRx to
Your Angular 6 Project
NgRx (Reactive Extensions for Angular) is becoming more and more popular in the Angular
community. It is a great way to manage state using the redux pattern and keep your
application scalable. When I first started using it, my biggest complaint was that it was a lot of
typing basically the same thing over and over. Thankfully, the NgRx team addressed this with
@ngrx/schematics. This package enhances the Angular CLI with new commands for NgRx. For
example, to create a new actions file, simply type: ng generate action ActionName
This first chapter is meant to help you get up and running quickly with NgRx by using the
@ngrx/schematics package. It is using NgRx version 6.01 so if it doesn’t look the same to you, it
could be things have changed. No knowledge of NgRx is necessary to read this post and setup
your project!
UPDATE
Note: Use the “ng add” command to achieve most of the things done using schematics in this
article. Run these commands for an existing project that doesn’t have NgRx:
After this completes, the only things necessary to do in this article will be the following:
Setup – under here, you may want to install the rest of the ngrx tools
NgRx Startup Code
Store Command – under here, you’ll have to add the “reducers” folder to a “store” folder to
get the same structure as in the post
Effect Command – under here you’ll have to add the “effects” folder (which wasn’t added for
you) to a “store” folder to get the same structure as in the post
Page 5 of 37
Setup
I start by creating a project using the standard Angular CLI command:
ng new ngrx-tutorial
This will give you the standard Angular starter project.
Now let’s install the NgRx schematics package:
“cli”: {
“defaultCollection”: “@ngrx/schematics”
}
Store Command
Now we can run the ‘store’ command:
Page 6 of 37
This command did the following:
Created a ‘store’ folder at the app level
Created a ‘reducers’ folder in the ‘store’ folder
Created an ‘index.ts’ file in the ‘reducers’ folder
This is the main reducer file for the root store (as opposed to feature store(s))
which contains:
State interface definition (empty)
reducers – ActionReducerMap (empty)
metaReducers – MetaReducer<State>[] (empty)
Imported the following to the AppModule:
StoreModule.forRoot(reducers, { metaReducers }),
Prepares the app for reducers and metaReducers
!environment.production?StoreDevtoolsModule.instrument() : []
Instruments the app for development
Effect Command
The next command to run is the “effect” command. It’s purpose is to get our first effect
registered with the application so it is ready to go.
This is the command to run:
Page 7 of 37
Conclusion
Getting up and running with NgRx is now quicker than ever with the @ngrx/schematics
package. Without knowing anything about NgRx, you can set up your project for it using best
practice code so that your team is ready to start using NgRx. In the next chapter, I'll cover some
of the other schematics commands to keep you productive as you code NgRx in Angular.
Page 8 of 37
Chapter 2: Actions, Reducers and
Effects
In the first chapter, I wrote about setting up NgRx in your Angular 6 application. Now it’s time
to focus on actions, reducers and effects. These are the heart and soul of your NgRx code and
will be the ones you use most on a day to day basis. You will learn what they are, how to
generate them, and how they work together in an Angular application.
The NgRx store is an implementation of the Redux pattern. Learn more about that here.
Actions and reducers are a big part of the redux pattern. Effects are NgRx constructs to help
with asynchronous operations.
Actions
Actions are objects that extend the NgRx Action class with a ‘type’ property. They have an
optional ‘payload’ property (naming is up to you but the standard is to name it ‘payload’) for
sending in data to the effect/reducer and are dispatched by the store to either run an effect or
change state in a reducer. So you can see that actions aren’t all that complicated but NgRx
schematics does generate action files for you and can help you standardize them in your
project.
To generate an action file, run this command:
ng generate action store/actions/auth
This generates the following file:
Page 9 of 37
Notes:
It generates a sample action
Notice the error – LoadsAuths on the last line should be Auth (or the Auth action should be
named LoadAuths – better yet)
This is an error with NgRx schematics but is no big deal as it gets you a
template to follow
The action constants are stored as an enum (AuthActionTypes)
The action class has a type (you can add optional payload)
The AuthActions type helps you to define all of your actions for Auth as a type – in the
reducer you’ll see why this is important
Notes:
Imports:
Store from @ngrx/store
import * as fromRoot… – this is where the main State interface lives in the
index.ts file
import * as authActions… – this is where our LoadAuths actions live
Page 10 of 37
Notes (cont.):
Inject the store
In the constructor, inject the store as shown in the code
When it’s time to dispatch (sometimes in ngOnInit, sometimes from a button click, etc.), run
this command:
this.store.dispatch(new authActions.LoadAuths());
Reducers
Reducers are pure functions that are the only ones that can change state. They aren’t really
changing state but making a copy of existing state and changing one or more properties on the
new state.
To generate a reducer file, run this command:
Page 11 of 37
The main reducer file (index.ts) was changed to this:
Notes:
It added import shown above
It added auth: fromAuth.State; to the State interface
It added auth: fromAuth.reducer to the reducers constant
Page 12 of 37
Updated auth.reducer.ts file:
Notes:
The userName property is added to State and initialState (not necessary for initialState of
course)
In the ‘reducer’ function, the action is changed to authActions.AuthActions (which is the
exported type AuthActions)
The case statement is added for SetAuths
I like to add a function to handle each action so the switch doesn’t get so
huge and ugly
The handleSetAuths function returns a new copy of state
The …state spread operator basically copies existing state
userName: action.payload then overwrites the userName property of State
(which is the only one at this time, but more should be added)
Page 13 of 37
Effects
Effects allow us to handle asynchronous operations in NgRx.
Most times this will be calling an API
The resulting data should be stored in state by returning an action for the reducer
Effects always return one or more actions (unless you decorate @Effect with {dispatch: false})
You can inject services into your effects as well so if you need to access those in NgRx,
effects are the place to do it
To generate an effect file, run this command:
Page 14 of 37
Create an Effect
The generated effect file doesn't give you a skeleton effect to follow like the action file does, so
I'll explain how you would do that here.
Here is the final effect (see notes below for explanation of how to create it):
Notes:
Decorate the effect with @Effect()
Name the effect using camel case of the action name and end with $ to denote it is an
Observable (loadAuths$)
The type of this variable should always be Observable<Action>
The 'ofType' function is what is triggering this effect - whenever LoadAuths is dispatched as
an action, this effect will run
Note it is using the string LoadAuths here and not the action class
Use http to do whatever you need to do, in this case log the user in and return the user
name
Return from the map a SetAuths action with the userName
This will automatically dispatch the SetAuths action to the
reducer to update the userName on state
If you want to return multiple actions, return an array of actions
Page 15 of 37
Project
So, over the last two chapters, this is how the project looks with NgRx:
I like to have the actions, effects and reducers in their own folder under a 'store' folder so that
they are easy to find. I have seen it done other ways - without a 'store' folder for example - but
this is my preference. In a future chapter, I'm going to talk about feature modules so I'll start
having one 'store' folder for each feature. So the pattern will reproduce itself many times in the
project.
Conclusion
In this chapter, you learned how to generate actions, reducers and effects using NgRx
schematics. You also learned what actions, reducers and effects are for and how they work
together to help you to manage state using NgRx in your Angular 6 application. In the next
chapter, I plan to show you how to access the state from your application.
Page 16 of 37
Chapter 3: Accessing State in the Store
In this chapter, we continue our NgRx Tutorial by showing how to access state in the store by
using selectors. It will complete the circle that started with dispatching an action, then an effect
doing asynchronous work and finally the reducer updating state in the store. The missing piece
is accessing that state in a component so that it can be displayed or used in various ways. For
purposes of demonstration, I will be simulating a login in my ‘auth’ slice of state and store a
user name and friendly name. This friendly name will be shown to the user on the welcome
page. I’ll of course use the Star Wars API to get the name.
This is the goal for the page output:
Code: github
This basically is the same as ng g component but adds the store to the constructor:
We’ll get back to this component later. First we need to understand how to access state from
the store using selectors.
Page 17 of 37
Add Selectors to the Auth Reducer
Before getting to selectors, I’m going to update the auth reducer as shown:
Notes:
Added ‘friendlyName’ to State – this will be shown on the welcome page
Updated handleSetAuths to take in more than just userName as payload (actions were also
updated with a SetAuthsPayload interface with userName and friendlyName as properties)
Auth Selectors
Now I’m ready to add selectors to this reducer. Selectors help us get at the data in the store by
using pure functions and keeping most of the logic on the store instead of in the components.
The first step with selectors is to add selectors in your reducer for each property of state as
follows:
These are just pure functions that take a State parameter and return a value on state. This will
be used in the main reducer file to create the selectors there.
Page 18 of 37
Selectors in the Main Reducer (index.ts)
It’s convention to put the selectors that everyone uses in the main reducer. For feature
modules, you’ll do it in the feature module’s main reducer (that’s a future post). These selectors
are the way for the consumer (usually components) to access a slice of state in the store. It
seems like a lot of busy work (and it is) but we do it this way so that it can be easily unit tested in
one spot (the reducers) and easily consumed from the components.
Here are the auth selectors:
Notes:
createFeatureSelector and createSelector are imported from ‘@ngrx/store’
selectAuthState: this creates a feature selector of type fromAuth.State (the state in the auth
reducer)
The ‘auth’ string must match the property in state
This will be used to get the auth State for the upcoming createSelector
functions
getUserName: this creates a selector using selectAuthState and our getUserName selector
we defined above
getFriendlyName: this creates a selector using selectAuthState and our getFriendlyName
selector we defined above
For a thorough look at selectors in NgRx, take a look at Todd Motto’s blog post on this topic.
Page 19 of 37
Add Friendly Name to the Welcome
Component
Now we are ready to access our friendly name that lives in auth state from our welcome
component.
This is our updated welcome component:
Notes:
First, define a ‘name$’ Observable<string> property
The html will reference this
Now, populate the name$ with this.store.select(fromStore.getFriendlyName)
This is using our selector created in the main reducer
Whenever this value is updated, it will automatically update the component
Notice the ‘async’ pipe. That is needed for Observables. It will handle the unsubscribing so
there’s no need for you to do it.
This code makes it super easy to access state and show it on your page. As an alternative, you
could have accessed state in this way:
This is problematic, though, because you have to do null checking and other work to ensure
you don’t get errors accessing the state. With the selector approach, that can be taken care of
in a centralized place and heavily unit tested.
Page 20 of 37
Update the Effect to get Star Wars Name
One last thing to do is update the LoadAuths effect so that it gets us person one from the Star
Wars API, namely Luke Skywalker.
Notice how SetAuths is now passing an object with userName and friendlyName. This will call
the SetAuths reducer and update state. Friendly name will finally appear on our welcome
component.
Conclusion
Accessing state in NgRx is extremely important and is what the components (mainly) consume.
It is done using state selectors that we define in the reducers. These selectors access a slice of
state and should be fully unit tested. With the knowledge gained in these first three chapters,
the reader should be able now to develop an Angular app using NgRx for state management.
The final piece of this puzzle is setting up feature modules with their own state and all that goes
with that. That will be tackled in upcoming chapters.
Page 21 of 37
Chapter 4: Add State to Feature
Module
Feature modules are Angular modules that group a bunch of components/services, etc. into a
module. This allows us to separate concerns nicely. Most likely, you’ve dealt with feature
modules if you have 1 month experience in Angular. Since feature modules can be lazy loaded
and because they are separate from the main app module, NgRx does things a little differently.
In this chapter, I plan to describe how to setup a lazy loaded feature module with NgRx.
The code is on github.
Page 22 of 37
This does the following:
Creates actions, effects and reducers folders with their respective files
ships.actions.ts, ships.effects.ts, ships.reducer.ts
Updates the starships module we created first thing as shown:
This gives us the ability to view state from a Chrome browser extension called Redux DevTools.
I’m also going to move the actions, effects and reducers folders under a “store” folder. I do this
so it’s easier to find all things NgRx within the feature module.
Last thing is to fix up the actions file because this is how it was generated:
Page 23 of 37
Reorganize the Starships Reducer
The way it’s setup now, the ships reducer is setup to handle only one reducer in the feature
module. That’s obviously not ideal so a little reorganization is in order.
First, I add some state to the ships reducer:
Page 24 of 37
Create Component to Show Starships
Now we are ready to create the component to show the starships and inject the store into the
component.
I’ll use this NgRx schematics command to generate a container:
The user$ variable is there to use the root part of state that we previously had retrieved (Luke
Skywalker)
The starships$ variable holds the results of state so initially it will be empty and then it will
load once state changes
Page 25 of 37
And then the component code:
Dispatch the LoadShips action to load the ships using the Star Wars API in the effect (see
code below)
Use the fromStore.getAllShips to get the ships from our feature module…here’s how this is
setup in the feature module index.ts reducer:
The ‘starships’ in the State interface must match the ‘starships’ in the selectStarshipsState
selector
And it must match the forFeature declaration in the feature module
Note that the “createFeatureSelector” command doesn’t match (as of 8/18/2018) what is in
the NgRx example app
That’s because it is a future thing that we don’t yet have access to (see Stack
Overflow)
selectShips gets the ‘ships’ property of StarshipsState
getAllShips then just gets the allShips property of fromShips.State
Page 26 of 37
LoadShips Action in the Effect
Here is the LoadShips action in the effect (which will call the Star Wars API to get the first ten
ships):
SetShips will then call the reducer function to update state as shown in ships.reducer:
Page 27 of 37
Redux DevTools to View State
I mentioned Redux DevTools, a Chrome extension, earlier. Let’s take a look at it now. It is a
useful tool when developing to see what is actually in state and the actions that got it that way.
Here is a screenshot of it for when we view the starships:
Notice that we have selected “[Ships] Set Ships”, that’s the action that calls the reducer to
change state
Load Ships is called before – that one got the ships from the API
“starships” is our feature name
“ships” is the property on StarshipsState
“allShips” is the property on the ships.reducer State
Page 28 of 37
How the Page Looks
If you are curious, here is my award-winning web page for showing the starships:
Conclusion
So that was quite a lot! But we were able to do the following:
1. Add a lazy loaded feature module (see the code on github for how to lazy load a module)
2. Add NgRx state to it
3. Prepare for future expansion within the feature module by reorganizing reducer code
4. Create a cool component using NgRx state
5. View the contents of the state in the browser using Redux DevTools
After these four chapters, you should be getting pretty good at using NgRx to manage state in
an Angular application. I’m sure most projects are using feature modules these days and being
able to manage state with NgRx is a valuable skill to learn.
Page 29 of 37
Chapter 5: Add Router Info to State
Adding Angular router information to state is very important for NgRx. Why, though, does it
matter if the Url, parameters and query parameters are stored in state? Good question! This
chapter aims to answer the question. I’ll be building upon the code that has been written in my
previous four posts on NgRx. I plan to add a starship detail page to the app which features the
Star Wars API.
The code is on github.
Page 30 of 37
Notes:
RouterStateUrl is an interface which defines what we want to store about the router
It can be anything that is on RouterStateSnapshot (however, there are some
things on RouterStateSnapshot that are not immutable and will break NgRx
store freeze)
The CustomSerializer class will basically be the code that copies things from the
RouterStateSnapshot into our RouterStateUrl interface and returns that
To get this code to run, you’ll have to add the following code to the
app.module:
Page 31 of 37
Notes:
Add the “router” property to the State interface
RouterReducerState is imported from @ngrx/router-store
The generic piece here is our RouterStateUrl interface defined previously
Add the “router” property to the ActionReducerMap
routerReducer is imported from @ngrx/router-store
selectReducerState creates our feature selector “router” which matches the property name
on State and the reducers map
getRouterInfo returns the RouterStateUrl interface we defined initially with the url, params
and queryParams – which is what we care most about
And that’s all there is to getting router information into state for our application. Be patient on
this, it seems like there is no reason for this but there is a big payoff for this coming (besides the
time-traveling.)
Page 32 of 37
To create the ship detail component, run this command:
This created a component with the store injected into the constructor nicely
It also defined it in the starships module
I’ll add this HTML code:
Page 33 of 37
This is all there is to the code! It works for any ship that is selected from the list of ships. The
magic here is in the fromStore.getCurrentShip selector. Let’s take a closer look at that.
The first arg in the createSelector function is the “getAllShips” selector – it returns all of the
starships in the store
The second arg “allShips” will take the ships passed in from “getAllShips” and use a regular
expression to grab the starship id from the url property on the starship
This is necessary so that it will be easy to find a starship by its id later
Until now, selectors have been pretty boring, but here you can see what else you can do with
them
Here is the getCurrentShip selector and our payoff with the router information:
Page 34 of 37
Notes:
Note that this works because the list of ships we get from the Star Wars API has the details in
it, so there is no need for another API call
If your code needs to get more detailed info, you can of course do that in an
effect
The first arg of the createSelector function is the “getAllShipsWithId” selector – so we can
easily match the id with the id in the router info
The second arg is the fromRoot.getRouterInfo selector which gives us the router info
The third arg takes both of these and finds the ship by id using the routerInfo.params.shipId
Note that when the shipId changes, this also changes our selector and the
component updates!
So for example, you could have a previous/next set of buttons
that allowed you to navigate up and down the list w/o going
back to the grid, this code would execute whenever the route
was navigated to
For this shipId parm to make sense, let’s look at the Starships routing
module:
Page 35 of 37
Results
Let’s take a look at how the site looks now. First, the list of starships has changed to add the id
(I guess you wouldn’t have to show the id) and a link in the name of the starship:
Page 36 of 37
Time Traveling
Finally, here is a look at the Redux DevTools after clicking the “stopwatch icon” on the bottom
row of buttons:
Notice the ROUTER_NAVIGATION entries – those are added there (partly) so we can travel
back in time to see the state at a given point, along with actual navigation happening on the
page!
Conclusion
Let’s recap:
1. Router information is now stored in state – the single source of truth now for our url,
parameters and query parameters
2. The parameters can now easily be accessed inside our selectors (or anywhere else for that
matter)
3. Our component now doesn’t have to have code that gets the id and then retrieves the ship,
it is all handled in the selector
4. We can do time-traveling using Redux DevTools now
5. We have some very clean code
It is my wish that you will take the information you’ve learned in these NgRx tutorials and use
them on your job effectively. Happy coding!
Page 37 of 37