Home » Angular 2 » How to Really use NgRX

How to Really use NgRX

I’ve talked around NgRX several times over the last few months but I’ve yet to write an article on how to use NgRX.  This is because I was under the impression that there were better articles available.  And while there are a lot of articles available, there is not anything I feel comfortable sending another programmer to who is trying to learn NgRX.

So, rather than spend a lot of time on why you want to learn NgRX, or arguing against some of the unfounded hesitations, today I’m just going to dive into how to use NgRX.

How to Really use NgRX
Photo credit: Bilal Kamoon via VisualHunt / CC BY

Project Assumptions

For the purposes of this post, I’m going to assume that you already have a basic project started using the Angular CLI.  For this post, I’m using version 1.0.1, but the steps should work the same for 1.0.0 as well.

You will also need to install NgRX.

npm install --save-dev @ngrx/store @ngrx/core @ngrx/effects

The Four Components

The NgRX model is composed of four basic elements: Stores, Reducers, Actions, and Effects.  Central to all of this is the store.  Let’s start there.

Store

The best way to think of a store is as a database made up of several tables.  While the store doesn’t have any of the fancy stuff associated with a database, it is a collection of smaller elements that most closely align with tables in a database.  The analogy isn’t perfect, but it is a start. I’ve found, this analogy clears up a lot of confusion for beginners.

Currently, we define our Store at the app.module level.  Most of the articles you will find online about how to use NgRX will have you defining the store in app.module.ts.  While this will work, in my own code, I create a separate module in a file named app.store.ts and import that module into app.module.  This keeps both my store definition code clean and isolated as well as keeping my app.module code clean.  Mixing concerns might make a great desert, but it is a terrible coding practice.

What follows is typically how I structure my store module, which we will import into our app module.

This varies a bit from what most of the other guys are teaching, so let me explain a bit.

I create the const reducers outside of the @NgModule definition because I want to be able to use that object in the @NgModule section and in the class, which we will talk about soon.

Next, we want to import this module into our main app.module.ts file

Reducers

Next in our list of files that we need to make NgRX work, are reducers.  The job of a reducer is to mutate the “table” in our store.  What is unique about reducers is that they are functions, not classes.

A generic reducer that doesn’t do a whole lot would look like this:

And now that we have a reducer, we need to add it to our app.store reducer const

Now that we have a reducer defined, we can subscribe to the “table” it represents in our store by selecting it from our store.  Most of the code you will see describing how to do this will look like this.

The problem with this, is that it is prone to error.  You could type in a string that looks something like what you want, but is off by a character.  I do that more often that I’d like to admit.  And strings don’t give you any intellisense.  We can fix both of those problems by giving our AppStores class static properties that return the string we are looking for.  This problem is commonly referred to as a “magic string” and I’ve written more about why this is bad in my article “Magic Strings and Magic Numbers

Now, you might think that all we are going to do is to create a field that returns the string we are looking for, but there is a chance, however small, that we could type that wrong.  So, we need to embellish the code a bit.

In the code above, you’ll see that we created a property named “generic” that passes AppStores.stores.generic to AppStores.checkForName.  What, exactly, is this doing?

Well, if you look at the code at line 24, you’ll see that we’ve created another static property called “stores”.  The first time it is called, it creates a map of properties to property names that it stores in the private field name _store.  Now, if you access a property name “generic” it returns the string, “generic”.

We then pass the string into checkForName to make sure that property really exists.  You could possibly mistype it, but the bigger save here is if you remove the reducer but forget to remove the associated property.

Now that we have this setup, we can replace

with

Actions

So far, all we’ve been able to do is to establish a “table” in a store and listen to is.  But, we have no way of actually changing the data.  This is where Actions come in.

Right now, our “generic” will return 0 every time it is called.  If we wanted to, we could create an action that will add one to generic every time the action is fired.  To make this more flexible, we can pass in how much to add.  Let’s create our first action.

an action is just an object with a type property and a payload property.  The type property is a string that describes what it is we want to do and the payload property is the data we want to use when that action is performed.

As a way of eliminating magic strings and redundancy, we setup our actions to look similar to this:

You will notice that everything is static and everything is public.  If you’ve read other articles, you will also notice that this is a bit different from how others might suggest that you set this up.  Others suggest that you make this class injectable and that you inject it into the class you want to use.

The reason I don’t is because injecting this into another class doesn’t add any value and actually complicates our code.  The reason you use dependency injection in the first place is so that you can replace out one object with another.  This is so you can mock out calls.  But Actions, by definition, provide no functionality.  They are simply convenience classes.  As I said, they eliminate redundancy and eliminate magic strings.  Why would you ever want to replace them?  If you are doing more than assigning data to your payload, you are doing something wrong.

One of the things I like about NgRX is that by using it, I reduce the number of parameters that need to be injected into my class.  By only needing to inject the store, rather than multiple services, and in this case even multiple Actions, my code becomes incredibly easy to maintain.

OK.  Enough with the architecture rant.  How do we use this action?

As I just mentioned, we inject the store into the class, which you should have already done when you subscribed to the store’s “table.”  This store object also has a dispatch function.  You dispatch the action object that gets returned and it gets sent off to the Reducer that should deal with it.

Now, let’s handle it in our reducer.

Remember, our reducer is just a basic function with a switch statement.  You can see that we access our static constant value “ADD” and added the payload to the existing state.

Now, it might be just a bit confusing here because when you look at the function parameters, you see that the default value for stat is zero.  But that is only true the first time this is run, which for our purposes is when the application is loaded.  Every time an action is fired, the state parameter has the current state from the last mutation.  So, our ADD switch is always adding to the most recent state and returning the value, which becomes our new current state.

Effects

Now, that’s the basics of NgRX.  But the question that remains to be answered is, “Where do I put my code to retrieve data?”

This is where Effects come in.  Think of Effects as “Side effects.”  What we have so far is very predictable.  Give a specific state, an action with a specific payload, the result will always be the same.  Very predictable.  Extremely testable.  If you add into this mix retrieving data all of that predictability goes away and we go back to needing mocks and injectables to test our logic.  Not something I’m a huge fan of doing.  So let’s leave the database access code out of the basic framework and instead put them in our Effects.

A basic Effect would look something like this.

Note, the constructor is where we inject specific objects that we will need for our code.  Each field decorated with @Effect is a separate observable that processes the logic.  This is typically used to get data from the database, but I’ve started considering how this might be put to use for things such as processing business rules.

You will also notice that the last line of an @Effect is an action.  This action is automatically dispatched to the store and processed by the appropriate reducer.  This is how the results of our ajax call make their way back to the store.

Again, I’ve deviated a bit from other articles you may have read.  Typically, you’ll see this code as calling out to a service which then calls out to the database.  I’ve put the Http code in the Effect.  I think for simple calls, this is fine.  If you really have a lot of setup to do prior to making a call a service might make more sense.

Finally, we’ll want to register this code in our app.stores.ts file.

This is a step I tend to forget and then I’m tearing my hair out trying to figure out why it never gets called.

File Locations

Before I end, I want to talk a bit about how to organize the code.

When I started with NgRX, I thought the best organization would be to have a directory for Actions, Reducers, Effects, and maybe one called Model where I keep my interface definitions for the stores (we’ll talk about those in a future post).  But, one of the most common criticisms of NgRX or Redux in general is the fact that you need so many files to get anything done.  Scattering them between directories doesn’t help.

So, I’ve since moved to putting all of the files related to a reducer under their own directory.  Similar to how you would put the html, css, spec and ts files together for a component.  This seems to make the code much more manageable.

Applications

In future posts, I will demonstrate how to use this pattern not just for a simple CRUD application.  You can find those in other articles.  But, also for error handling, wait states, and more.  Don’t forget to sign up for our newsletter if you haven’t already.  Use the box at the top of this screen.

 

Other post in Angular 2
Summary
How to Really use NgRX
Article Name
How to Really use NgRX
Description
I’ve talked around NgRX several times over the last few months but I’ve yet to write an article on how to use NgRX. This is because I was under the impression that there were better articles available. And while there are a lot of articles available, there is not anything I feel comfortable sending another programmer to who is trying to learn NgRX. So, rather than spend a lot of time on why you want to learn NgRX, or arguing against some of the unfounded hesitations, today I’m just going to dive into how to use NgRX.
Author
DMB Consulting, LLC

Related Post

  • Awesome Angular2 Architecture Options and OpinionsAwesome Angular2 Architecture Options and Opinions On the subject of Angular2 Architecture, the perception is that Angular 2 is a highly-opinionated architecture.  But even though there is a style guide for Angular 2, there are a lot of […]
  • Dynamically Add Components in AngularDynamically Add Components in Angular This past week, I ran into a need to dynamically add components using Angular.  My specific reason for doing this is that the component I am using is a port of an AngularJS component and […]
  • Dissecting Angular 2 ModulesDissecting Angular 2 Modules In the new world of Angular 2, and even in the world of Angular.js, you might feel like the concept of a module is the most difficult to wrap your head around. This is especially if you’ve […]
  • Jedi Angular 2 Tips and TricksJedi Angular 2 Tips and Tricks This week, I thought I’d collect a list of unrelated tricks and tips I’ve learned over the last couple of weeks into one post.  Unless you love to read documentation, or you’ve run into […]
  • Amazing Angular2 DOM Tips, Tricks, and WarningsAmazing Angular2 DOM Tips, Tricks, and Warnings I’ve been working with Angular2 now since RC0 and I’ve learned quite a few things about Angular2 DOM tips, tricks, and warnings that you’ll want to pay attention to as you get […]

About Dave Bush

Dave Bush is a Full Stack ASP.NET developer. His commitment to quality through test driven development, vast knowledge of C#, HTML, CSS and JavaScript as well as his ability to mentor younger programmers and his passion for Agile/Scrum as defined by the Agile Manifesto and the Scrum Alliance will certainly be an asset to your organization.

(1) Comment

Leave a Reply

Your email address will not be published. Required fields are marked *