Day 21 Challenge: Implementing Redux in Angular for State Management

sunny gsunny g
4 min read

Objective:

This challenge is designed to help you learn how to implement Redux in an Angular application for state management. Redux is a predictable state container, and using it in Angular will help you understand how to manage the global state of your application in a clean and scalable way.

By the end of this challenge, you'll have a basic Angular application with Redux-style state management implemented.


Concepts to Understand:

  1. Redux Architecture:

    • State: The entire state of the application is stored in a single object.

    • Actions: These are plain objects that describe what happened in the application (e.g., button click, form submission).

    • Reducers: Functions that determine how the application's state changes based on actions.

    • Store: A centralized location that holds the state of the application.

    • Dispatch: The method that sends actions to the reducer, updating the state.

  2. NgRx:

    • NgRx is the official Redux implementation for Angular. It integrates Redux with Angular applications and follows a similar pattern of state management.

    • In this challenge, you will use NgRx to implement the Redux pattern.


Challenge Steps:

Part 1: Set up an Angular Project with NgRx

  1. Create an Angular Project:

    • If you don't have an Angular project already, create one using Angular CLI:

        ng new angular-redux-challenge --routing --style=scss
        cd angular-redux-challenge
      
  2. Install NgRx Dependencies:

    • Install the necessary NgRx packages for state management:

        ng add @ngrx/store
      
  3. Generate an Angular Service for state management (e.g., app/store/app.state.ts).


Part 2: Define Redux Store (State, Actions, Reducers)

  1. Define the State:

    • Create a file app/store/app.state.ts to define the structure of your application's state.
    export interface AppState {
      counter: number;
    }

    export const initialState: AppState = {
      counter: 0
    };
  1. Create Actions:

    • Create actions to interact with the state (e.g., increment and decrement counter). In app/store/app.actions.ts:
    import { createAction } from '@ngrx/store';

    export const increment = createAction('[Counter] Increment');
    export const decrement = createAction('[Counter] Decrement');
    export const reset = createAction('[Counter] Reset');
  1. Create Reducer:

    • Implement the reducer to handle state changes based on actions. In app/store/app.reducer.ts:
    import { createReducer, on } from '@ngrx/store';
    import { increment, decrement, reset } from './app.actions';
    import { AppState, initialState } from './app.state';

    export const appReducer = createReducer(
      initialState,
      on(increment, (state) => ({ ...state, counter: state.counter + 1 })),
      on(decrement, (state) => ({ ...state, counter: state.counter - 1 })),
      on(reset, (state) => ({ ...state, counter: 0 }))
    );

Part 3: Set up Store and Dispatch Actions in Components

  1. Configure Store in app.module.ts:

    • Import StoreModule from @ngrx/store and add it to the imports array.
    import { NgModule } from '@angular/core';
    import { BrowserModule } from '@angular/platform-browser';
    import { StoreModule } from '@ngrx/store';
    import { appReducer } from './store/app.reducer';
    import { AppComponent } from './app.component';

    @NgModule({
      declarations: [AppComponent],
      imports: [
        BrowserModule,
        StoreModule.forRoot({ appState: appReducer })
      ],
      providers: [],
      bootstrap: [AppComponent]
    })
    export class AppModule {}
  1. Dispatch Actions and Select State in app.component.ts:

    • In app.component.ts, use Store to dispatch actions and select the state.
    import { Component } from '@angular/core';
    import { Store } from '@ngrx/store';
    import { Observable } from 'rxjs';
    import { increment, decrement, reset } from './store/app.actions';
    import { AppState } from './store/app.state';

    @Component({
      selector: 'app-root',
      template: `
        <div class="container">
          <h1>Counter: {{ counter$ | async }}</h1>
          <button (click)="increment()">Increment</button>
          <button (click)="decrement()">Decrement</button>
          <button (click)="reset()">Reset</button>
        </div>
      `,
      styleUrls: ['./app.component.scss']
    })
    export class AppComponent {
      counter$: Observable<number>;

      constructor(private store: Store<{ appState: AppState }>) {
        this.counter$ = store.select(state => state.appState.counter);
      }

      increment() {
        this.store.dispatch(increment());
      }

      decrement() {
        this.store.dispatch(decrement());
      }

      reset() {
        this.store.dispatch(reset());
      }
    }

Part 4: Test and Measure Performance

  1. Test the Application:

    • Run the Angular application:

        ng serve
      
    • Open the browser and go to http://localhost:4200. The page should display the counter value and have buttons to increment, decrement, and reset the counter. The actions should update the state and reflect on the UI.

  2. Debugging:

  • Use Redux DevTools to inspect actions, state changes, and history of actions.

    • Install Redux DevTools in Chrome or Firefox.

    • Open the DevTools and inspect the Redux state changes during interactions.


Evaluation Criteria:

  • Correctness: The application should correctly dispatch actions and reflect state changes (e.g., counter should increment and decrement correctly).

  • State Management: Ensure that the store, actions, and reducers are set up properly and interacting as expected.

  • Scalability: Understand how the Redux pattern scales for larger applications with more actions, reducers, and state slices.

  • Best Practices: Proper use of NgRx features (e.g., createAction, createReducer) and immutability in state handling.


Solution Recap:

  1. State (app.state.ts): Defines the shape of the application’s state.

  2. Actions (app.actions.ts): Specifies actions like increment, decrement, and reset.

  3. Reducer (app.reducer.ts): Updates the state based on the actions dispatched.

  4. Store Configuration (app.module.ts): Integrates StoreModule and the reducer into the application.

  5. Component (app.component.ts): Dispatches actions and selects the current state to update the UI.


This challenge will help you understand how Redux-style state management works in Angular using NgRx, and it will also introduce you to concepts like actions, reducers, and the store for managing state efficiently across your application.

0
Subscribe to my newsletter

Read articles from sunny g directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

sunny g
sunny g