State Management in Angular using NgRx

Manikandan S
6 min readJun 21, 2020

--

In this blog, let’s create a simple Angular application using NgRx for state management.

What is NgRx?

NgRx is a State management library based on RxJs Observables for Angular applications. It is similar to Redux in the React world and is based on the principles of Redux architecture —

  1. Single source of truth — global state of the application is stored in an object tree in a single store.
  2. State is read only — Basically your components cannot directly mutate the state. State can be updated only by emitting an action which invokes the reducers and update the state.
  3. Changes are made using Pure Functions — Reducers are pure functions that takes 2 parameters — the action and the previous state and returns the new state.
  4. Unidirectional data flow — components dispatch actions, actions invoke reducers, reducers update state, the state change is passed to the view

When do we need NgRx?

  1. In large scale angular applications, when we need to share data between multiple angular components in the component tree. Sharing data via @Input and @Output between components will lead to unnecessary props in the intermediate components and will increase complexity as the number of intermediate components increases.
  2. When it is possible for more than one component (or via server push) in your application to mutate the same data. Have a look at this video which explains this issue faced in face book.
  3. NgRx also helps decouple component interaction. For example, the component which is listening to changes on a piece of data doesn’t know which component changed the data and vice-versa.

In small applications, we can still share data across components in the component tree via angular services and RxJs Subjects. Refer here for how to implement this.

Building the sample app:

Let’s build a simple CRUD app that tracks movies list. We’ll build the application in 2 parts to keep things iterative.

Part 1 — Read an initial state of movies from the store and display in the Movie List Component.

Part 2 — Add actions to add and delete movies and update the store

You can see final code here — https://github.com/manikandan031/ngrx-movies-app

Part 1 — Steps

  1. Bootstrap out new angular app — ngrx-movies-app.
  2. Define the Application initial state with a list of movies.
  3. Creating the Movies Reducer.
  4. Creating the Movies Selector.
  5. Creating the Movie List component

1. Bootstrap our new angular app

Run the command ng new ngrx-movies-app to generate our angular application.

Add the NgRx dependencies

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

Test your application by running npm start and navigating to http://localhost:4200. You should be able to see the default angular page.

Open the ngrx-movies-app folder in your IDE, clear the contents of app.component.html and add the following

<h2>NgRx Movies Tracker</h2>

2. Define the application initial state with a list of movies

Let’s create a MovieModel interface to represent the movies.

Let’s define an initial state with a couple of movies and in the next steps we’ll select this data from the state and display in our movie-list-component.

Let’s first create the MovieState with an initial state as shown below.

Now, let’s create the AppState which imports the movie state. This structure will allow us to define specific states for each feature and finally import all of them and compose the global app state.

3. Creating the Movies Reducer

Next step is to define the Reducer. In Part 1, we’ll define the reducer with just the initial state using the createReducer NgRx function. We’ll be adding what are called as Ons in Part 2 which will take the action and the previous state and returns the new state.

Create an index.ts file that maps the states and their reducers.

Go to app.module.ts and import the StoreModule as follows

StoreModule.forRoot(reducers)

where reducers is what we exported from the index.ts file

4. Creating the Movies selector

The Selectors are used to access parts of your global state. It helps decouple the components that needs to access parts of the state from directly accessing it via the store. We’ll use the createSelector NgRx function.

5. Create the Movie list component

The last step of Part 1 is to create the Movie List component, use the selector to select movies and display it.

Note that, Once this is done, any changes happening to the movies list in the store will automatically reflect in the movie list component.

Let’s also create the html to render the movies list.

Go to app.component.html and add the movie-list component tag below the page header as below

<h2>NgRx Movies Tracker</h2>
<app-movie-list></app-movie-list>

Now start the application by running npm start and go to http://localhost:4200 . You should be able to see the initial movies list on the screen.

Part 2 — Steps

Now let’s introduce the Add and Delete Movie features.

  1. Creating addMovie and deleteMovie NgRx Actions
  2. Adding addMovie and deleteMovie Ons in the moviesReducer
  3. Creating the form to add movie and dispatch addMovie action on submit
  4. Adding Delete movie button and dispatch deleteMovie action on click
  5. Creating addMovie and deleteMovie NgRx Actions

We’ll use the NgRx createAction function to create our Actions as below.

The createAction function takes 2 arguments — a unique name for the action and the payload/input which the reducer will receive and act on . You can see that we pass the new Movie model as the payload for Add Movie and id of the deleted movie as payload for delete.

It’s a good practice to namespace our actions by Prefixing the Domain/Feature (in our case we have used [Movie] as prefix) to avoid collisions with other actions in our application.

2. Adding addMovie and deleteMovie Ons in the moviesReducer

Next step is to update our movies reducer to define how the state should change when each of our actions are dispatched. We’ll use the NgRx “On” function to define these as below.

The “on” takes the action and a function as parameters. This function will run when the action is dispatched. It takes the previous state and the payload as arguments and returns the new state.

Notice that we don’t directly push the new movie model into the movies array. Instead we use the array spread (…) operator and add the new movie from the payload. This way we don’t mutate the existing state but simply create a new array.

Again for the delete operation, we don’t mutate the existing array but create a new array with all except the deleted movie using the filter operation.

3. Creating the form to add movie and dispatch addMovie action on submit

Next step is to create a reactive form to add new movies and dispatch the addMovie action. Let’s create a new component MovieFormComponent for this purpose.

The MovieForm Component has a simple reactive form with 2 fields — id and name. We inject the NgRx store object into the movie form component via the constructor which it will use to dispatch the addMovie action. Notice that the store dispatch function takes the action function along with the payload as input.

We’ll invoke the addMovie() function when the ‘Add Movie’ button is clicked.

Add the movie-form component just below the movie-list component in the app component as below

<h2>NgRx Movies Tracker</h2>
<app-movie-list></app-movie-list>
<app-movie-form></app-movie-form>

4. Adding Delete movie button and dispatch deleteMovie action on click

The Last step is to update our movie-list component for delete movie functionality. We add a ‘Delete’ button next to each movie and similar to the add movie operation, we inject the store object into the movie-list component and invoke the dispatch function when a movie is deleted.

We are done. Now run your application and enjoy.. :)

--

--

Manikandan S

A full stack software developer since 2008 who loves writing code.