Welcome to our comprehensive guide on Angular's Store, Actions, and Reducers! In this lesson, we will dive deep into these essential concepts, making them easy to understand for beginners while providing enough depth for intermediate learners.
In Angular applications, the Store is a central data structure for managing application state. Actions are events triggered by user interactions or system events, and Reducers are pure functions responsible for updating the state based on the dispatched actions.
Let's take a closer look at each component:
The Store in Angular is implemented using NgRx, a popular library for managing application state. It provides a centralized place for managing shared state across components, services, and other parts of the application.
Actions are events that trigger the Reducer to update the state. They represent user interactions or system events that lead to changes in the application state.
Reducers are pure functions that handle the changes to the state based on dispatched actions. They take the current state and an action as input and return the updated state.
To illustrate how Store, Actions, and Reducers work together, let's create a simple example application that manages a list of todos.
To install NgRx, run the following command:
npm install @ngrx/store @ngrx/effects --savetodos module:ng generate module todos --route todostodos.module.ts, import the StoreModule and NgReducerStoreModule:import { StoreModule } from '@ngrx/store';
import { NgReduxStoreModule } from '@ngrx/store';
@NgModule({
imports: [
StoreModule.forFeature('todos', reducers),
NgReduxStoreModule
]
})
export class TodosModule { }todos.actions.ts file and define the initial actions:import { createAction, props } from '@ngrx/store';
export const LoadTodos = createAction('[Todos] Load Todos');
export const LoadTodosSuccess = createAction(
'[Todos] Load Todos Success',
props<{ todos: any[] }>()
);
export const LoadTodosFailure = createAction(
'[Todos] Load Todos Failure',
props<{ error: any }>()
);todos.reducers.ts file and define the initial state and reducer:import { createReducer, on } from '@ngrx/store';
import * as TodosActions from './todos.actions';
export const initialState: any = {
todos: [],
loading: false,
error: null
};
export const todosReducer = createReducer(
initialState,
on(TodosActions.LoadTodos, state => ({ ...state, loading: true })),
on(TodosActions.LoadTodosSuccess, (state, { todos }) => ({ ...state, loading: false, todos })),
on(TodosActions.LoadTodosFailure, (state, { error }) => ({ ...state, loading: false, error }))
);todos.service.ts to fetch and store the todos data:import { Injectable } from '@angular/core';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { TodosActions, TodosActionTypes } from './todos.actions';
import { catchError, map, mergeMap } from 'rxjs/operators';
@Injectable()
export class TodosEffects {
loadTodos$ = createEffect(() =>
this.actions$.pipe(
ofType(TodosActionTypes.LoadTodos),
mergeMap(() => this.todosService.getTodos().pipe(
map(todos => TodosActions.LoadTodosSuccess({ todos })),
catchError(error => of(TodosActions.LoadTodosFailure({ error })))
))
)
);
constructor(
private actions$: Actions,
private todosService: TodosService
) {}
}todos.module.ts:import { StoreModule } from '@ngrx/store';
import { NgReduxStoreModule } from '@ngrx/store';
import { EffectsModule } from '@ngrx/effects';
import { TodosEffects } from './todos.effects';
@NgModule({
imports: [
StoreModule.forFeature('todos', reducers),
NgReduxStoreModule,
EffectsModule.forFeature([TodosEffects])
]
})
export class TodosModule { }Now that we have set up the Store, Actions, and Reducers, we can use them in our components to manage the todos data.
import { Component, OnInit } from '@angular/core';
import { Store, select } from '@ngrx/store';
import * as TodosActions from './todos.actions';
@Component({
selector: 'app-todos',
templateUrl: './todos.component.html',
styleUrls: ['./todos.component.css']
})
export class TodosComponent implements OnInit {
todos$ = this.store.pipe(select('todos'));
constructor(private store: Store) { }
ngOnInit(): void {
this.store.dispatch(TodosActions.LoadTodos);
}
}Question: Which Angular library manages the Store in the provided example?
A: NgRx B: Angular CLI C: NgStore Correct: A Explanation: NgRx is the library that manages the Store in the provided example.
That's it for our first lesson on Angular's Store, Actions, and Reducers! In the next lessons, we'll dive deeper into more advanced topics and best practices. Stay tuned! 🎯