Lab 18 : NgRx — Gestion d'état Redux
📖 Ressources
Section intitulée « 📖 Ressources »🚀 Code de départ
Section intitulée « 🚀 Code de départ »album-wholesale-v16
Dans ce lab, vous ajouterez une gestion d’état centralisée à l’application album wholesale en utilisant NgRx classic (@ngrx/store + @ngrx/effects). Vous gérerez la liste des albums et l’état de chargement via un store Redux, remplacerez les appels de service directs dans les composants par des dispatches et sélecteurs, et debuggerez avec Redux DevTools.
📝 Instructions
Section intitulée « 📝 Instructions »Étape 1 : Installer NgRx
Section intitulée « Étape 1 : Installer NgRx »npm install @ngrx/store @ngrx/effects @ngrx/store-devtoolsÉtape 2 : Définir l’état, les actions et le reducer
Section intitulée « Étape 2 : Définir l’état, les actions et le reducer »Créez src/app/store/album/album.actions.ts :
import { createAction, props } from '@ngrx/store';import { Album } from '../../model/album.model';
export const loadAlbums = createAction('[Album] Load Albums');export const loadAlbumsSuccess = createAction( '[Album] Load Albums Success', props<{ albums: Album[] }>());export const loadAlbumsFailure = createAction( '[Album] Load Albums Failure', props<{ error: string }>());Créez src/app/store/album/album.reducer.ts :
import { createReducer, on } from '@ngrx/store';import { Album } from '../../model/album.model';import { loadAlbums, loadAlbumsSuccess, loadAlbumsFailure } from './album.actions';
export interface AlbumState { albums: Album[]; loading: boolean; error: string | null;}
const initialState: AlbumState = { albums: [], loading: false, error: null,};
export const albumReducer = createReducer( initialState, on(loadAlbums, state => ({ ...state, loading: true })), on(loadAlbumsSuccess, (state, { albums }) => ({ ...state, albums, loading: false })), on(loadAlbumsFailure, (state, { error }) => ({ ...state, error, loading: false })));Étape 3 : Créer un sélecteur
Section intitulée « Étape 3 : Créer un sélecteur »Créez src/app/store/album/album.selectors.ts :
import { createFeatureSelector, createSelector } from '@ngrx/store';import { AlbumState } from './album.reducer';
export const selectAlbumState = createFeatureSelector<AlbumState>('albums');
export const selectAllAlbums = createSelector( selectAlbumState, state => state.albums);
export const selectAlbumsLoading = createSelector( selectAlbumState, state => state.loading);Étape 4 : Créer un effet
Section intitulée « Étape 4 : Créer un effet »Créez src/app/store/album/album.effects.ts :
import { Injectable } from '@angular/core';import { Actions, createEffect, ofType } from '@ngrx/effects';import { switchMap, map, catchError, of } from 'rxjs';import { AlbumService } from '../../services/album.service';import { loadAlbums, loadAlbumsSuccess, loadAlbumsFailure } from './album.actions';
@Injectable()export class AlbumEffects { loadAlbums$ = createEffect(() => this.actions$.pipe( ofType(loadAlbums), switchMap(() => this.albumService.findAll().pipe( map(albums => loadAlbumsSuccess({ albums })), catchError(error => of(loadAlbumsFailure({ error: error.message })) ) ) ) ) );
constructor( private actions$: Actions, private albumService: AlbumService ) {}}Étape 5 : Câbler le store dans AppModule
Section intitulée « Étape 5 : Câbler le store dans AppModule »Ouvrez src/app/app.module.ts et ajoutez les modules NgRx dans le tableau imports :
import { StoreModule } from '@ngrx/store';import { EffectsModule } from '@ngrx/effects';import { StoreDevtoolsModule } from '@ngrx/store-devtools';import { albumReducer } from './store/album/album.reducer';import { AlbumEffects } from './store/album/album.effects';
@NgModule({ declarations: [ /* ... */ ], imports: [ BrowserModule, HttpClientModule, // ... autres imports existants StoreModule.forRoot({ albums: albumReducer }), EffectsModule.forRoot([AlbumEffects]), StoreDevtoolsModule.instrument({ maxAge: 25 }), ], bootstrap: [AppComponent]})export class AppModule {}Étape 6 : Utiliser le store dans un composant
Section intitulée « Étape 6 : Utiliser le store dans un composant »Remplacez l’appel direct au service dans AlbumListComponent :
import { Store } from '@ngrx/store';import { loadAlbums } from '../../store/album/album.actions';import { selectAllAlbums, selectAlbumsLoading } from '../../store/album/album.selectors';
export class AlbumListComponent implements OnInit { private store = inject(Store);
albums$ = this.store.select(selectAllAlbums); loading$ = this.store.select(selectAlbumsLoading);
ngOnInit() { this.store.dispatch(loadAlbums()); }}<mat-progress-bar *ngIf="loading$ | async" mode="indeterminate"></mat-progress-bar>
<app-album-card *ngFor="let album of albums$ | async" [album]="album"></app-album-card>Étape 7 : Vérifier avec Redux DevTools
Section intitulée « Étape 7 : Vérifier avec Redux DevTools »Installez l’extension Chrome Redux DevTools et inspectez :
- Chaque action dispatchée
- L’état avant et après chaque action
- Le débogage par voyage dans le temps (time-travel)
Comparez votre résultat avec le dossier de référence album-wholesale-v16-ngrx.

