Introduction To ngrx In Angular

In Angular, ngrx is built on the concept of Redux, a state management container. In ngrx, this state management is achieved by a store.

Any application built on ngrx will have three main components.

  • Store
  • Actions
  • Reducers

Store

A store acts just like a client-side database. Whenever any data is needed, the application gets it from the store.

Reducers

Reducers act as tables in the store. A reducer is a pure function that takes two arguments - one is the state of the store and the second one is any payload data (optional).

A simple reducer can be like this.

  1. export interface Reducer<T> {  
  2.   (state: T, action: Action): T;  
  3. }  

Actions

Actions are the source of communication between store and reducers. Any change in the state of the store is done by the actions.

Actions are composed of type and any payload data.

A simple action can be like this.

  1. export interface Action {  
  2.   type: string;  
  3.   payload?: any;  
  4. }  

Effects

In ngrx, any server-side call can be done in effects. Ngrx/effect is the place where we put our async calls.

Angular Set up

Make a blank project of Angular. Now, install the ngrx in your project using the following command.

npm install @ngrx/core @ngrx/effects @ngrx/store –save

After successful installation, let's first define our state of the store. Our application state can be defined as the composition of different models. A state is simply bound to any model. A state is always an interface.

Let’s define the state of the applications. For this, create some model of the state. Navigate to the app folder and create a folder named model and create a TypeScript file like I have made a mode named “authModel”.

Add the following code.

  1. export interface Details  
  2. {  
  3.     part1:Number,  
  4.     part2:Number,  
  5.     part3:Number  
  6. }  

Next is defining the state of this model. Create a folder named state and create “authState”.

  1. import * as AuthModel from '../models/authModel'  
  2. export interface AuthState{     
  3.     data:AuthModel.Details  
  4. }  

Create a new file named appState. This will contain all of the states of the application.

  1. import { AuthState } from '../state/authState'  
  2. export interface AppState {  
  3.      authState:AuthState  
  4. }  

Now, our state is ready. Next is to write some actions for the state. Create a folder named Actions in your App folder.

Create a TypeScript file for actions. Add the following code.

  1. import {Action} from '@ngrx/store'  
  2.   
  3. export const GET_AUTH_INFO='GET_AUTH_INFO'  
  4.   
  5. export class GetAuthInfo implements Action {  
  6.     readonly type=GET_AUTH_INFO;  
  7.     constructor(public payload:any) { }  
  8. }  
  9. export  type AuthActions = GetAuthInfo;  

Let’s create a reducer for this action. Create a folder named reducers and add “authReducer”. Add the following code in it. 

  1. import {ActionReducer,Action} from '@ngrx/store';  
  2. import * as authActions from '../actions/actions'  
  3. import * as authModel from '../models/authModel';  
  4. import {AppState} from '../state/appstate';  
  5. import {AuthState} from '../state/authState';  
  6.   
  7. const initialState: AuthState= { data : null }   
  8. export function authReducer(state : AuthState =initialState, actions:authActions.AuthActions) : any  
  9. {  
  10.     
  11.     switch (actions.type)  
  12.     {  
  13.         case authActions.GET_AUTH_INFO:  
  14.   
  15.         state.data.part1=1*actions.payload;  
  16.         state.data.part2=2+actions.payload;  
  17.         state.data.part3=3+actions.payload;  
  18.         return state;  
  19.         default:  
  20.         let data = {  
  21.             
  22.                 part1: 0,  
  23.                 part2: 1,  
  24.                 part3: 2,  
  25.               
  26.         }  
  27.         return Object.assign({}, state, { data });  
  28.   
  29.     }  
  30. }   

This is the simple reducer that is taking some values from the payload and after doing some mathematical operations, changing the state of the store.

By default, it is assigning some values to the state. Now, you can have an action reducer map for mapping different states with the reducers. Create one more file named app.reducer.ts and add the following code.

  1. import { ActionReducerMap } from '@ngrx/store'  
  2. import { AppState } from '../state/appstate';  
  3. import {AuthState} from '../state/authState'  
  4. import * as AuthReducer from './authReducer';  
  5.   
  6. export interface State  {  
  7.     authReducer:AuthState;  
  8. }  
  9. export const reducers: ActionReducerMap<State> ={  
  10.    authReducer:AuthReducer.authReducer  
  11. }  

Now, let's register our reducers and store in app.module.

  1. import {StoreModule} from '@ngrx/store';  
  2. import {reducers} from './reducers/app.reducers';  

Here, we are importing the store module from ngrx and reducers of the app. Now, register them in imports sections by adding the following line.

StoreModule.forRoot(reducers),

Next, let’s call this store in our app component. Add the following code in your app component.

  1. import { Component } from '@angular/core';  
  2. import * as authActions from './actions/actions'  
  3. import {Store} from '@ngrx/store';  
  4. import {Observable} from  'rxjs';  
  5. import {Details} from '../app/models/authModel'  
  6. import * as fromRoot from './reducers/app.reducers';  
  7. import {authReducer} from './reducers/authReducer'  
  8. import {ReducerConstants} from './reducers/reducerConstants'  
  9. @Component({  
  10.   selector: 'app-root',  
  11.   templateUrl: './app.component.html',  
  12.   styleUrls: ['./app.component.css']  
  13. })  
  14. export class AppComponent {  
  15.   title = 'app';  
  16.   number:any;  
  17.   protected data:Observable<Details>  
  18.   constructor(public store:Store<any>){  
  19.     this.store.select('authReducer').subscribe(data=>{  
  20.        console.log(data);  
  21.        this.data=data.data;  
  22.      });  
  23.   }  
  24.   valueChanged(num:any)  
  25.   {  
  26.     if(!num)  
  27.     return;  
  28.     let payload:number=parseInt(num);  
  29.     this.store.dispatch(new authActions.GetAuthInfo(payload));  
  30.   }  
  31. }  

Now, call this function valueChanged in HTML. Place this htm in app.compoment.html.

  1. <input type="text" [(ngModel)]="number" (ngModelChange)="valueChanged(number)"/>  
  2. {{data.part1}}  
  3. {{data.part2}}  
  4. {{data.part3}}  

Now, after adding the value, an action will be dispatched from the app component and then, it will update the state of the store.

This code demonstrates a simple app with the implementation of ngrx in Angular.