Introducció a NgRx Effects

NgRx Effects és una biblioteca que permet gestionar efectes secundaris en una aplicació Angular utilitzant el patró Redux. Els efectes secundaris són operacions que no modifiquen l'estat directament, com ara sol·licituds HTTP, interaccions amb serveis externs, o qualsevol altra operació asíncrona. NgRx Effects ajuda a mantenir el codi net i organitzat, separant la lògica d'efectes secundaris de la lògica de gestió d'estat.

Objectius d'aquest tema:

  • Comprendre què són els efectes en NgRx.
  • Aprendre a crear i gestionar efectes amb NgRx Effects.
  • Veure exemples pràctics d'ús d'efectes per gestionar sol·licituds HTTP.

Conceptes Clau

Què són els efectes?

Els efectes són classes que contenen lògica per gestionar operacions asíncrones i altres efectes secundaris. Utilitzen observables per escoltar accions i emetre noves accions en resposta.

Per què utilitzar NgRx Effects?

  • Separació de preocupacions: Manté la lògica d'efectes secundaris fora dels reducers.
  • Testabilitat: Els efectes es poden provar fàcilment de manera aïllada.
  • Escalabilitat: Facilita la gestió de lògica complexa i asíncrona en aplicacions grans.

Configuració de NgRx Effects

Instal·lació

Per començar a utilitzar NgRx Effects, primer cal instal·lar el paquet @ngrx/effects:

npm install @ngrx/effects

Configuració bàsica

Després d'instal·lar el paquet, cal configurar NgRx Effects en el mòdul principal de l'aplicació:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { StoreModule } from '@ngrx/store';
import { EffectsModule } from '@ngrx/effects';
import { AppComponent } from './app.component';
import { reducers } from './store/reducers';
import { MyEffects } from './store/effects/my-effects';

@NgModule({
  declarations: [AppComponent],
  imports: [
    BrowserModule,
    StoreModule.forRoot(reducers),
    EffectsModule.forRoot([MyEffects])
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule {}

Creació d'Efectes

Exemple pràctic: Sol·licitud HTTP

Suposem que volem fer una sol·licitud HTTP per obtenir una llista d'usuaris. Primer, definim les accions necessàries:

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

export const loadUsers = createAction('[User] Load Users');
export const loadUsersSuccess = createAction(
  '[User] Load Users Success',
  props<{ users: User[] }>()
);
export const loadUsersFailure = createAction(
  '[User] Load Users Failure',
  props<{ error: any }>()
);

Definició de l'efecte

Ara, creem una classe d'efectes per gestionar la sol·licitud HTTP:

import { Injectable } from '@angular/core';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { of } from 'rxjs';
import { catchError, map, mergeMap } from 'rxjs/operators';
import { UserService } from '../services/user.service';
import * as UserActions from '../actions/user.actions';

@Injectable()
export class UserEffects {
  loadUsers$ = createEffect(() =>
    this.actions$.pipe(
      ofType(UserActions.loadUsers),
      mergeMap(() =>
        this.userService.getUsers().pipe(
          map(users => UserActions.loadUsersSuccess({ users })),
          catchError(error => of(UserActions.loadUsersFailure({ error })))
        )
      )
    )
  );

  constructor(
    private actions$: Actions,
    private userService: UserService
  ) {}
}

Explicació del codi

  • Actions: És un flux d'accions que NgRx proporciona per permetre escoltar accions específiques.
  • createEffect: Crea un efecte que escolta accions i emet noves accions en resposta.
  • ofType: Filtra les accions per tipus.
  • mergeMap: Permet gestionar operacions asíncrones i emetre múltiples accions.
  • catchError: Gestiona errors i emet una acció de fallada.

Exercici Pràctic

Objectiu

Crear un efecte que faci una sol·licitud HTTP per obtenir dades de productes i gestioni les accions de càrrega, èxit i fallada.

Passos

  1. Definir les accions:

    import { createAction, props } from '@ngrx/store';
    
    export const loadProducts = createAction('[Product] Load Products');
    export const loadProductsSuccess = createAction(
      '[Product] Load Products Success',
      props<{ products: Product[] }>()
    );
    export const loadProductsFailure = createAction(
      '[Product] Load Products Failure',
      props<{ error: any }>()
    );
    
  2. Crear el servei:

    import { Injectable } from '@angular/core';
    import { HttpClient } from '@angular/common/http';
    import { Observable } from 'rxjs';
    import { Product } from '../models/product.model';
    
    @Injectable({
      providedIn: 'root'
    })
    export class ProductService {
      private apiUrl = 'https://api.example.com/products';
    
      constructor(private http: HttpClient) {}
    
      getProducts(): Observable<Product[]> {
        return this.http.get<Product[]>(this.apiUrl);
      }
    }
    
  3. Definir l'efecte:

    import { Injectable } from '@angular/core';
    import { Actions, createEffect, ofType } from '@ngrx/effects';
    import { of } from 'rxjs';
    import { catchError, map, mergeMap } from 'rxjs/operators';
    import { ProductService } from '../services/product.service';
    import * as ProductActions from '../actions/product.actions';
    
    @Injectable()
    export class ProductEffects {
      loadProducts$ = createEffect(() =>
        this.actions$.pipe(
          ofType(ProductActions.loadProducts),
          mergeMap(() =>
            this.productService.getProducts().pipe(
              map(products => ProductActions.loadProductsSuccess({ products })),
              catchError(error => of(ProductActions.loadProductsFailure({ error })))
            )
          )
        )
      );
    
      constructor(
        private actions$: Actions,
        private productService: ProductService
      ) {}
    }
    
  4. Configurar l'efecte en el mòdul:

    import { NgModule } from '@angular/core';
    import { BrowserModule } from '@angular/platform-browser';
    import { StoreModule } from '@ngrx/store';
    import { EffectsModule } from '@ngrx/effects';
    import { AppComponent } from './app.component';
    import { reducers } from './store/reducers';
    import { ProductEffects } from './store/effects/product-effects';
    
    @NgModule({
      declarations: [AppComponent],
      imports: [
        BrowserModule,
        StoreModule.forRoot(reducers),
        EffectsModule.forRoot([ProductEffects])
      ],
      providers: [],
      bootstrap: [AppComponent]
    })
    export class AppModule {}
    

Resum

En aquest tema, hem après què són els efectes en NgRx i com utilitzar NgRx Effects per gestionar operacions asíncrones i altres efectes secundaris en una aplicació Angular. Hem vist com crear i configurar efectes, així com un exemple pràctic de sol·licitud HTTP. Els efectes ajuden a mantenir el codi net, organitzat i fàcil de provar, millorant la mantenibilitat i escalabilitat de l'aplicació.

Curs d'Angular

Mòdul 1: Introducció a Angular

Mòdul 2: Components d'Angular

Mòdul 3: Enllaç de dades i directives

Mòdul 4: Serveis i injecció de dependències

Mòdul 5: Enrutament i navegació

Mòdul 6: Formularis a Angular

Mòdul 7: Client HTTP i observables

Mòdul 8: Gestió d'estat

Mòdul 9: Proves a Angular

Mòdul 10: Conceptes avançats d'Angular

Mòdul 11: Desplegament i millors pràctiques

© Copyright 2024. Tots els drets reservats