In Angular, we use state management libraries like ngrx to handle complex data flows in large applications. ngrx is a reactive state management library based on the Redux pattern, which provides a way to manage state changes in Angular applications. It uses Observables, Actions, Reducers, and Effects to manage state changes.
In this blog, we will discuss the steps to use ngrx in an Angular application and understand its flow.
Step 1: Install ngrx
First, we need to install ngrx using the npm package manager.
npm install @ngrx/store --save
Step 2: Define the state
The state is the data that we want to manage in the application. We define the state using an interface in a separate file. For example, we can define a state interface for a counter application as follows:
typescript
export interface CounterState {
count: number;
}
Step 3: Define the actions
Actions describe the changes that occur in the application. We define actions using an enum in a separate file. For example, we can define actions for a counter application as follows:
typescript
import { createAction } from ‘@ngrx/store’;
export enum CounterActionTypes {
Increment = ‘[Counter] Increment’,
Decrement = ‘[Counter] Decrement’,
}
export const increment = createAction(
CounterActionTypes.Increment
);
export const decrement = createAction(
CounterActionTypes.Decrement
);
Step 4: Define the reducers
Reducers specify how the application state changes in response to actions. We define reducers in a separate file. For example, we can define reducers for a counter application as follows:
typescript
import { createReducer, on } from ‘@ngrx/store’;
import { CounterActionTypes } from ‘./counter.actions’;
import { CounterState } from ‘./counter.state’;
export const initialState: CounterState = {
count: 0,
};
export const counterReducer = createReducer(
initialState,
on(CounterActionTypes.Increment, (state) => ({
count: state.count + 1,
})),
on(CounterActionTypes.Decrement, (state) => ({
count: state.count – 1,
}))
);
Step 5: Define the effects
Effects are used for handling asynchronous operations, such as HTTP requests. We define effects in a separate file. For example, we can define effects for a counter application as follows:
typescript
import { Injectable } from ‘@angular/core’;
import { Actions, createEffect, ofType } from ‘@ngrx/effects’;
import { Observable, of } from ‘rxjs’;
import { map, catchError, mergeMap } from ‘rxjs/operators’;
import { CounterActionTypes, increment } from ‘./counter.actions’;
@Injectable()
export class CounterEffects {
increment$ = createEffect(() =>
this.actions$.pipe(
ofType(CounterActionTypes.Increment),
mergeMap(() =>
this.myService.increment().pipe(
map(() => increment()),
catchError(() => of({ type: ‘API Error’ }))
)
)
)
);
constructor(private actions$: Actions, private myService: MyService) {}
}
Step 6: Register the state, actions, reducers, and effects
We register the state, actions, reducers, and effects in the app.module.ts file as follows:
typescript
import { NgModule } from ‘@angular/core’;
import { BrowserModule } from ‘@angular/platform-browser’;
import { AppComponent } from ‘./app.component’;
import { StoreModule } from ‘@ngrx/store’;
import { EffectsModule } from ‘@ngrx/effects’;
import { counterReducer } from ‘./counter.reducer’;
import { CounterEffects } from ‘./counter.effects’;
@NgModule({
declarations: [AppComponent],
imports: