DEV Community

Indraja
Indraja

Posted on

State Management in Angular with NgRx: A Complete Guide

Introduction

Managing state in large Angular applications can become challenging. This is where NgRx comes in! NgRx is a state management library based on the Redux pattern, designed specifically for Angular applications.

In this guide, we'll explore:

  • Why you need NgRx in Angular
  • The core concepts of NgRx
  • How to implement NgRx step-by-step
  • Best practices for efficient state management

Let's get started!

πŸ”₯ Why Use NgRx?

Before jumping into implementation, let's understand why NgRx is beneficial:

βœ… Centralized State Management - Stores data in a single place, making it predictable.

βœ… Time-Travel Debugging - Inspect and revert state changes.

βœ… Optimized Performance - Uses immutable state updates for better performance.

βœ… Scalability - Suitable for large, complex applications.

πŸ› οΈ Installing NgRx in Angular

To get started with NgRx, install the necessary packages:

ng add @ngrx/store @ngrx/effects @ngrx/store-devtools
Enter fullscreen mode Exit fullscreen mode

This command adds NgRx Store, Effects, and DevTools for debugging.


πŸ—οΈ Understanding NgRx Core Concepts

NgRx consists of several key building blocks:

1️⃣ Actions

Actions define events that describe what happens in the app.

import { createAction, props } from '@ngrx/store';

export const loadUsers = createAction('[User] Load Users');
export const loadUsersSuccess = createAction('[User] Load Users Success', props<{ users: any[] }>());
export const loadUsersFailure = createAction('[User] Load Users Failure', props<{ error: string }>());
Enter fullscreen mode Exit fullscreen mode

2️⃣ Reducers

Reducers specify how state changes in response to actions.

import { createReducer, on } from '@ngrx/store';
import { loadUsersSuccess } from './user.actions';

export interface UserState {
  users: any[];
}

const initialState: UserState = {
  users: []
};

export const userReducer = createReducer(
  initialState,
  on(loadUsersSuccess, (state, { users }) => ({ ...state, users }))
);
Enter fullscreen mode Exit fullscreen mode

3️⃣ Selectors

Selectors help retrieve specific parts of the state.

import { createSelector, createFeatureSelector } from '@ngrx/store';
import { UserState } from './user.reducer';

export const selectUserState = createFeatureSelector<UserState>('user');
export const selectUsers = createSelector(selectUserState, (state) => state.users);
Enter fullscreen mode Exit fullscreen mode

4️⃣ Effects

Effects handle side effects like API calls.

import { Injectable } from '@angular/core';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { UserService } from '../services/user.service';
import { loadUsers, loadUsersSuccess } from './user.actions';
import { mergeMap, map } from 'rxjs/operators';

@Injectable()
export class UserEffects {
  loadUsers$ = createEffect(() =>
    this.actions$.pipe(
      ofType(loadUsers),
      mergeMap(() => this.userService.getUsers()
        .pipe(map(users => loadUsersSuccess({ users })))
      )
    )
  );

  constructor(private actions$: Actions, private userService: UserService) {}
}
Enter fullscreen mode Exit fullscreen mode

πŸ› οΈ Integrating NgRx in an Angular Module

Add the store and effects module to your app module:

import { NgModule } from '@angular/core';
import { StoreModule } from '@ngrx/store';
import { EffectsModule } from '@ngrx/effects';
import { userReducer } from './store/user.reducer';
import { UserEffects } from './store/user.effects';

@NgModule({
  imports: [
    StoreModule.forRoot({ user: userReducer }),
    EffectsModule.forRoot([UserEffects])
  ]
})
export class AppModule {}
Enter fullscreen mode Exit fullscreen mode

Using NgRx in Angular Components

πŸ” Selecting Data from Store

Use select to get data from the store:

import { Component } from '@angular/core';
import { Store } from '@ngrx/store';
import { selectUsers } from './store/user.selectors';

@Component({
  selector: 'app-user-list',
  template: `<ul><li *ngFor="let user of users$ | async">{{ user.name }}</li></ul>`
})
export class UserListComponent {
  users$ = this.store.select(selectUsers);

  constructor(private store: Store) {}
}
Enter fullscreen mode Exit fullscreen mode

πŸ—οΈ Dispatching Actions

Dispatch actions to update state:

this.store.dispatch(loadUsers());
Enter fullscreen mode Exit fullscreen mode

Best Practices for NgRx

βœ… Use Selectors for optimized state retrieval.

βœ… Keep Effects independent from components.

βœ… Use Immutable State - always return new objects in reducers.

βœ… Organize your store into feature modules for scalability.


πŸ“Œ Conclusion

NgRx provides a powerful way to manage application state in Angular. By using Actions, Reducers, Selectors, and Effects, you can create scalable and maintainable applications.

Have any questions? Drop them in the comments! πŸ‘‡


πŸ’‘ Further Reading:

πŸ“Œ NgRx Official Documentation

πŸ“Œ Redux Pattern Explained

Happy coding! πŸŽ‰

Top comments (0)