Swiftorial Logo
Home
Swift Lessons
Matchups
CodeSnaps
Tutorials
Career
Resources

State Management with NgRx

1. Introduction

State management is a crucial aspect of building applications. When applications grow, managing state can become complex. NgRx provides a framework for managing state in Angular applications using the Redux pattern.

2. NgRx Concepts

Key Concepts

  • Store: The single source of truth for the application state.
  • Actions: Events that describe something that happened in the application.
  • Reducers: Pure functions that take the current state and an action to return a new state.
  • Selectors: Functions to query and retrieve specific pieces of state.
  • Effects: Side effects that handle asynchronous operations.

3. Installation

To add NgRx to your Angular project, run the following command:

ng add @ngrx/store @ngrx/effects @ngrx/store-devtools

4. Store

The store is where your application state lives. You define the store in your application module.

import { StoreModule } from '@ngrx/store';
import { reducer } from './reducer';

@NgModule({
    imports: [
        StoreModule.forRoot({ state: reducer }),
    ],
})
export class AppModule { }

5. Actions

Actions are dispatched to change the state. Define actions using the following syntax:

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

export const addItem = createAction('[Item] Add Item', (item: string) => ({ item }));

6. Reducers

Reducers are pure functions that take the current state and an action, and return the new state.

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

export const initialState = [];

const _itemReducer = createReducer(
    initialState,
    on(addItem, (state, { item }) => [...state, item])
);

export function itemReducer(state, action) {
    return _itemReducer(state, action);
}

7. Effects

Effects enable side effects in your application, such as API calls. Use the following pattern:

import { Injectable } from '@angular/core';
import { Actions, ofType, createEffect } from '@ngrx/effects';
import { of } from 'rxjs';
import { catchError, map, mergeMap } from 'rxjs/operators';
import { ApiService } from './api.service';
import { addItem } from './actions';

@Injectable()
export class ItemEffects {
    loadItems$ = createEffect(() => this.actions$.pipe(
        ofType('[Item] Load Items'),
        mergeMap(() => this.api.getItems()
            .pipe(
                map(items => ({ type: '[Item] Load Items Success', items })),
                catchError(() => of({ type: '[Item] Load Items Failure' }))
            ))
    ));

    constructor(private actions$: Actions, private api: ApiService) {}
}

8. Selectors

Selectors are used to retrieve slices of state from the store:

import { createSelector } from '@ngrx/store';

export const selectItems = state => state.items;

export const selectItemCount = createSelector(
    selectItems,
    (items) => items.length
);

9. Best Practices

  • Keep state minimal and flat.
  • Use actions to describe state changes clearly.
  • Utilize selectors for efficient state retrieval.
  • Test reducers and effects thoroughly.
  • Keep the store immutable.

10. FAQ

What is NgRx?

NgRx is a state management library for Angular applications based on the Redux pattern.

When should I use NgRx?

Use NgRx when your application state becomes complex and hard to manage with simple services.

Can I use NgRx without Redux?

No, NgRx is built on the Redux pattern and relies on actions, reducers, and a store.