NgRx used for developing reactive angular applications. @ngrx/store is used to store the data in a container and dispatch it using the set of predefined actions. It will be very useful while developing huge applications which consists of many components and services. In this type of applications if we store the service data in a store we can access the data in all other components using store selectors.

State management is handled using Store for the application, the data is stored in the store and accessed from the store in the form of states.

In this article we are doing how to create a store, dispatch the data into store, get the data from store using selectors.

You can refer the example here:

https://github.com/KtreeOpenSource/AngularExamples/tree/master/ngrxDemo

Step:1 – Create new angular project

Creating the new angular project by running the command

ng new ngrxDemo

This will create ngrxDemo angular repository.

Step:2 – Install ngrx schematics

Install ngrx schematics package by running the command

npm install @ngrx/schematics –save-dev

This will install @ngrx/schematics library in node modules.

Step:3 – Setup ngrx schematics Setup the ngrx schematics as default collection in angular projects by running the command

ng config cli.defaultCollection @ngrx/schematics

This command will add the following in angular.json file.

Step:4 – Install @ngrx/core, @ngrx/store, @ngrx/store-devtools Install @ngrx/core, @ngrx/store and @ngrx/store-devtools by running the command using npm

npm install @ngrx/core @ngrx/store @ngrx/store-devtools –save

This will install @ngrx/core, @ngrx/store and @ngrx/store-devtools libraries in node modules.

Step:5 – Create store and reducer

Run the command to create store, reducers folders and index.ts file in reducers folder

. ng generate store State –root –statePath store/reducers –module app.module.ts

This command also imports the store module in app.module.ts

import { StoreModule } from ‘@ngrx/store’;
import { reducers, metaReducers } from ‘./store/reducers’;
import { StoreDevtoolsModule } from ‘@ngrx/store-devtools’;
import { environment } from ‘../environments/environment’;
imports: [
BrowserModule,
StoreModule.forRoot(reducers, { metaReducers }),
!environment.production ? StoreDevtoolsModule.instrument() : []
],

Step:6 – Create actions

Actions: NgRx actions are used to dispatch the data to store. The actions consists of ‘type‘ property and ‘payload’ as optional property. The actions types are unique they are to store the data in different states.

Create the action by running the command

ng generate action store/actions/user

This will create user.actions.ts in store/actions folder. .src/app/store/actions/user.actions.ts

import { Action } from ‘@ngrx/store’;
export enum UserActionTypes {
LoadUsers = ‘[User] Load Users’,
}
export class LoadUsers implements Action {
readonly type = UserActionTypes.LoadUsers;
}
export type UserActions = LoadUsers;

Step:7 – Create reducers

Reducers: Reducers are pure functions used to change state. They are not really change states, every time they will copy the state and modify only one or parameters depending on actions.

Create a reducer by running the command

ng generate reducer store/reducers/user –reducers index.ts

This command will create the user.reducer.ts file in store/reducers folder and updates the index.ts file in reducers folder.

.src/app/store/reducers/user.reducer.ts

import { Action } from ‘@ngrx/store’;
export interface State { }
export const initialState: State = {};
export function reducer(state = initialState, action: Action): State {
switch (action.type) {
default:
return state;
}
}

This reducer is added to the main reducer.

.src/app/store/reducers.index.ts

import * as fromUser from ‘./user.reducer’;
export interface State {
user: fromUser.State;
}
export const reducers: ActionReducerMap<State> = {
user: fromUser.reducer,
};

Step:8 – Create app service

In this step we are creating the service to get the data from users.json

.src/assets/data/users.json

[{
"id": 1,
"userName": "test1",
"email": "test1@gmail.com"
},{
"id": 2,
"userName": "test2",
"email": "test@gmail.com"
},{
"id": 3,
"userName": "test3",
"email": "test3@gmail.com"
},{
"id": 4,
"userName": "test4",
"email": "test4@gmail.com"
}]

Creating the service by running the command

ng generate service /services/app

This will create app service in services folder. Create a action in the service to get the data from users.json file.

.src/app/services/app.service.ts

import { Injectable } from ‘@angular/core’;
import { HttpClient } from ‘@angular/common/http’;
@Injectable({
providedIn: ‘root’
})
export class AppService {
constructor(private http: HttpClient) { }
getUser() {
return this.http.get(‘assets/data/users.json’);
}
}

Import the HttpClientModule in app.module.ts

import { HttpClientModule } from ‘@angular/common/http’;
imports: [
BrowserModule,
StoreModule.forRoot(reducers, { metaReducers }),
!environment.production ? StoreDevtoolsModule.instrument() : [],
HttpClientModule
],

Step:9 – Dispatch data to the store

Import the service in the app.component, get the users data from users.json using the service and dispatch the data to the store.

Add the users payload to the LoadUsers action

.src/app/store/actions/user.actions.ts

export class LoadUsers implements Action {
constructor(
public users: any
) { }
readonly type = UserActionTypes.LoadUsers;
}

Add users state in the user reducer to store the data to the store.

.src/app/store/reducers/user.reducer.ts

import { UserActions, UserActionTypes } from ‘../actions/user.actions’;
export interface State {
users: any;
}
export const initialState: State = {
users: []
};
export function reducer(state = initialState, action: UserActions): State {
switch (action.type) {
case UserActionTypes.LoadUsers:
return { …state, users: action.users };
default:
return state;
}
}

Import the store in app component to dispatch the users data to store.

.src/app/app.component.ts

import { Component, OnInit } from ‘@angular/core’;
import { AppService } from ‘./services/app.service’;
import { Store } from ‘@ngrx/store’;
import * as fromStore from ‘./store/reducers/index’;
import * as UserActions from ‘./store/actions/user.actions’;
@Component({
selector: ‘app-root’,
templateUrl: ‘./app.component.html’,
styleUrls: [‘./app.component.css’]
})
export class AppComponent implements OnInit {
constructor(
private appService: AppService,
public store: Store<fromStore.State>
) { }
ngOnInit() {
this.appService.getUser().subscribe(res => {
this.store.dispatch(new UserActions.LoadUsers(res));
});
}
}

Here dispatching the users data into the store by using the users actions.

Step:10 – Create user component

Create the other component and data from the store

Here creating user component by running the command

ng generate component /components/userComponent

This will create user-component in components folder

.src/app/components/user-component/user-component.component.html

<p>
user-component works!
</p>

.src/app/components/user-component/user-component.component.ts

import { Component, OnInit } from ‘@angular/core’;
@Component({
selector: ‘app-user-component’,
templateUrl: ‘./user-component.component.html’,
styleUrls: [‘./user-component.component.css’]
})
export class UserComponentComponent implements OnInit {
constructor() { }
ngOnInit() { }
}

Step:11 – Select the users data from the store

Import the store in the user component to get the users data from the store.

.src/app/components/user-component/user-component.component.ts

import { Store } from ‘@ngrx/store’;
import * as fromStore from ‘../../store/reducers/index’;
public users = [];
constructor(public store: Store < fromStore.State >) { }
ngOnInit() {
this.store.select(‘user’).subscribe(res => {
this.users = res.users;
})
}

.src/app/components/user-component/user-component.component.html

<div>
<ul>
<li *ngFor="let user of users">
<p>Username: {{user.userName}}</p>
<p>Email: {{user.email}}</p>
</li>
</ul>
</div>

Step:12 – Create selectors

Selectors: Selectors are pure functions used to get the slice of the state. Using these selectors we can get only particular store, so every time if we update the other stores these selectors subscribe won’t trigger.

Creating selector in user reducer

.src/app/store/reducers/user.reducer.ts

export const getUsers = (state: State) => state.users;

Import the selector in main reducer

.src/app/store/reducers/index.ts

import {
ActionReducer,
ActionReducerMap,
createFeatureSelector,
createSelector,
MetaReducer
} from ‘@ngrx/store’;
export const selectUserState = createFeatureSelector < fromUser.State > (‘user’);
export const getUserName = createSelector(selectUserState, fromUser.getUsers);

Here getUserName selector is created to get the users from the store

Step:13 – Get the data from selectors

Getting the data from user store using selector

.src/app/components/user-component/user-component.component.ts

getUsersFromSelectors() {
this.store.select(fromStore.getUserName).subscribe(res => {
console.log(res);
});
}