Skip to content

Comment utiliser les effect sur NgRx ?

Intérêt ?

Les effets de NgRx vous permettent de séparer les effets de côté-effets de votre application de votre logique de mise à jour de l'état. Cela peut être utile pour plusieurs raisons :

  • Séparation de la responsabilité : en séparant les effets de côté-effets de votre logique de mise à jour de l'état, vous pouvez mieux structurer votre code et rendre chaque partie de votre application plus facile à comprendre et à maintenir.
  • Testabilité : en séparant les effets de côté-effets de votre logique de mise à jour de l'état, vous pouvez les tester de manière plus facile et plus fiable. Vous pouvez également tester votre logique de mise à jour de l'état de manière plus facile en sachant que les effets de côté-effets ont été correctement gérés.
  • Performances : en exécutant les effets de côté-effets de manière asynchrone, vous pouvez éviter de bloquer le thread principal de votre application et améliorer les performances de votre application.

Voici un schéma qui illustre le fonctionnement des effets de NgRx :

mermaid
sequenceDiagram
Store->>Effect: Action dispatched
Effect->>Service: Call service method
Service->>Effect: Return data or error
Effect->>Store: Dispatch new action
sequenceDiagram
Store->>Effect: Action dispatched
Effect->>Service: Call service method
Service->>Effect: Return data or error
Effect->>Store: Dispatch new action
  1. Un utilisateur de l'application dispatch une action.
  2. L'action est envoyée au store de NgRx, qui la transmet à l'effet correspondant.
  3. L'effet appelle une méthode d'un service (par exemple, une méthode qui exécute une requête HTTP).
  4. Le service exécute la logique appropriée et retourne une réponse (des données ou une erreur).
  5. L'effet traite la réponse et dispatch une nouvelle action au store de NgRx.

Installer

npm install @ngrx/effects
npm install @ngrx/effects

Utiliser les effects

Pour utiliser les effets de NgRx, vous devrez d'abord inclure l'import suivant dans votre fichier de module d'application :

ts
import { EffectsModule } from '@ngrx/effects';
import { EffectsModule } from '@ngrx/effects';

Ensuite, vous devrez définir un effet en créant une classe qui étend la classe Effect de NgRx. Vous devrez également fournir une source d'actions à écouter en utilisant l'opérateur ofType de la bibliothèque @ngrx/effects. Voici un exemple de ce à quoi pourrait ressembler une classe d'effet simple :

ts
import { Injectable } from '@angular/core';
import { Effect, Actions, ofType } from '@ngrx/effects';
import { Observable, map, tap } from 'rxjs';
import * as myActions from './actions';

@Injectable()
export class MyEffects {
  @Effect()
  effect$: Observable<Action> = this.actions$.pipe(
    ofType<myActions.ActionOne>(myActions.ActionTypes.ACTION_ONE),
    tap(() => console.log('Action One Dispatched!')),
    map(() => new myActions.ActionTwo())
  );

  constructor(private actions$: Actions) {}
}
import { Injectable } from '@angular/core';
import { Effect, Actions, ofType } from '@ngrx/effects';
import { Observable, map, tap } from 'rxjs';
import * as myActions from './actions';

@Injectable()
export class MyEffects {
  @Effect()
  effect$: Observable<Action> = this.actions$.pipe(
    ofType<myActions.ActionOne>(myActions.ActionTypes.ACTION_ONE),
    tap(() => console.log('Action One Dispatched!')),
    map(() => new myActions.ActionTwo())
  );

  constructor(private actions$: Actions) {}
}

Pour enregistrer cet effet auprès de votre module d'application, vous devrez l'inclure dans la liste des fournisseurs du module et l'ajouter à la liste des effets du module en utilisant EffectsModule.forFeature ou EffectsModule.forRoot. Voici un exemple de ce à quoi pourrait ressembler l'enregistrement d'un effet dans votre module d'application :

ts
@NgModule({
  imports: [
    EffectsModule.forRoot([MyEffects])
  ],
  providers: [MyEffects]
})
export class AppModule {}
@NgModule({
  imports: [
    EffectsModule.forRoot([MyEffects])
  ],
  providers: [MyEffects]
})
export class AppModule {}

Vous pouvez également enregistrer plusieurs effets dans un module en utilisant EffectsModule.forFeature et en fournissant un tableau d'effets au lieu d'un seul effet.

Qu'est ce que le type Actions ?

Voici comment fonctionne Actions :

  • Lorsqu'une action est dispatchée dans votre application, elle est ajoutée au flux d'actions géré par Actions.
  • L'effet écoute ce flux d'actions en utilisant l'opérateur ofType de la bibliothèque @ngrx/effects. Cet opérateur permet de filtrer les actions du flux en fonction de leur type.
  • Lorsqu'une action correspondant au type spécifié est dispatchée, l'effet réagit en exécutant la logique définie pour cette action.

Exemple avec des requêtes HTTP

Voici un exemple d'effet de NgRx qui fait appel à un service qui exécute une requête HTTP :

ts
import { Injectable } from '@angular/core';
import { Effect, Actions, ofType } from '@ngrx/effects';
import { Observable } from 'rxjs';
import { map, switchMap, catchError } from 'rxjs/operators';
import * as myActions from './actions';
import { MyService } from './my.service';

@Injectable()
export class MyEffects {
  @Effect()
  loadData$: Observable<Action> = this.actions$.pipe(
    ofType<myActions.LoadData>(myActions.ActionTypes.LOAD_DATA),
    switchMap(() =>
      this.myService.getData().pipe(
        map(data => new myActions.LoadDataSuccess(data)),
        catchError(error => of(new myActions.LoadDataFail(error)))
      )
    )
  );

  constructor(private actions$: Actions, private myService: MyService) {}
}
import { Injectable } from '@angular/core';
import { Effect, Actions, ofType } from '@ngrx/effects';
import { Observable } from 'rxjs';
import { map, switchMap, catchError } from 'rxjs/operators';
import * as myActions from './actions';
import { MyService } from './my.service';

@Injectable()
export class MyEffects {
  @Effect()
  loadData$: Observable<Action> = this.actions$.pipe(
    ofType<myActions.LoadData>(myActions.ActionTypes.LOAD_DATA),
    switchMap(() =>
      this.myService.getData().pipe(
        map(data => new myActions.LoadDataSuccess(data)),
        catchError(error => of(new myActions.LoadDataFail(error)))
      )
    )
  );

  constructor(private actions$: Actions, private myService: MyService) {}
}

Dans cet exemple :

  • L'effet écoute les actions de type LOAD_DATA.
  • Lorsqu'une action de ce type est dispatchée, l'effet appelle la méthode getData de MyService. Cette méthode exécute une requête HTTP pour récupérer des données à partir d'un serveur.
  • Si la requête HTTP réussit, l'effet dispatch une action de type LOAD_DATA_SUCCESS avec les données obtenues en réponse.
  • Si la requête HTTP échoue, l'effet dispatch une action de type LOAD_DATA_FAIL avec l'erreur retournée par le serveur.