NgRx Store és una llibreria per a Angular que proporciona un patró de gestió d'estat inspirat en Redux. Utilitza un únic estat immutable i accions per modificar-lo, facilitant la gestió de l'estat de l'aplicació de manera previsible i escalable.

Objectius del Mòdul

  • Comprendre els conceptes bàsics de NgRx Store.
  • Aprendre a configurar NgRx Store en una aplicació Angular.
  • Crear accions, reducers i selectors.
  • Integrar NgRx Store amb components Angular.

Conceptes Clau

Estat Centralitzat

NgRx Store utilitza un únic estat centralitzat per a tota l'aplicació, el qual és immutable. Això significa que qualsevol canvi en l'estat crea una nova còpia de l'estat en lloc de modificar l'existent.

Accions

Les accions són objectes que descriuen un canvi en l'estat. Cada acció té un tipus i, opcionalment, un payload (dades addicionals).

Reducers

Els reducers són funcions pures que prenen l'estat actual i una acció, i retornen un nou estat. Són responsables de gestionar com l'estat canvia en resposta a les accions.

Selectors

Els selectors són funcions que permeten accedir a parts específiques de l'estat de manera eficient.

Configuració de NgRx Store

Instal·lació

Per començar a utilitzar NgRx Store, primer cal instal·lar les dependències necessàries:

npm install @ngrx/store @ngrx/effects @ngrx/store-devtools

Configuració Bàsica

  1. Definir l'Estat Inicial:

    export interface AppState {
      counter: number;
    }
    
    export const initialState: AppState = {
      counter: 0,
    };
    
  2. Crear Accions:

    import { createAction } from '@ngrx/store';
    
    export const increment = createAction('[Counter] Increment');
    export const decrement = createAction('[Counter] Decrement');
    export const reset = createAction('[Counter] Reset');
    
  3. Crear Reducer:

    import { createReducer, on } from '@ngrx/store';
    import { increment, decrement, reset } from './counter.actions';
    import { AppState, initialState } from './app.state';
    
    const _counterReducer = createReducer(
      initialState,
      on(increment, (state) => ({ ...state, counter: state.counter + 1 })),
      on(decrement, (state) => ({ ...state, counter: state.counter - 1 })),
      on(reset, (state) => ({ ...state, counter: 0 }))
    );
    
    export function counterReducer(state: AppState | undefined, action: Action) {
      return _counterReducer(state, action);
    }
    
  4. Registrar el Reducer en el Mòdul:

    import { NgModule } from '@angular/core';
    import { StoreModule } from '@ngrx/store';
    import { counterReducer } from './counter.reducer';
    
    @NgModule({
      imports: [
        StoreModule.forRoot({ counter: counterReducer }),
      ],
    })
    export class AppModule {}
    
  5. Utilitzar Selectors:

    import { createSelector, createFeatureSelector } from '@ngrx/store';
    import { AppState } from './app.state';
    
    export const selectCounterState = createFeatureSelector<AppState>('counter');
    
    export const selectCounter = createSelector(
      selectCounterState,
      (state: AppState) => state.counter
    );
    
  6. Integrar amb Components:

    import { Component } from '@angular/core';
    import { Store } from '@ngrx/store';
    import { Observable } from 'rxjs';
    import { AppState } from './app.state';
    import { increment, decrement, reset } from './counter.actions';
    import { selectCounter } from './counter.selectors';
    
    @Component({
      selector: 'app-counter',
      template: `
        <div>
          <h1>{{ counter$ | async }}</h1>
          <button (click)="increment()">Increment</button>
          <button (click)="decrement()">Decrement</button>
          <button (click)="reset()">Reset</button>
        </div>
      `,
    })
    export class CounterComponent {
      counter$: Observable<number>;
    
      constructor(private store: Store<AppState>) {
        this.counter$ = this.store.select(selectCounter);
      }
    
      increment() {
        this.store.dispatch(increment());
      }
    
      decrement() {
        this.store.dispatch(decrement());
      }
    
      reset() {
        this.store.dispatch(reset());
      }
    }
    

Exercicis Pràctics

Exercici 1: Crear una Acció Personalitzada

  1. Crea una nova acció set que permeti establir el valor del comptador a un valor específic.
  2. Modifica el reducer per gestionar aquesta nova acció.
  3. Actualitza el component per utilitzar aquesta acció.

Solució:

  1. Crear Acció:

    export const set = createAction('[Counter] Set', props<{ value: number }>());
    
  2. Modificar Reducer:

    const _counterReducer = createReducer(
      initialState,
      on(increment, (state) => ({ ...state, counter: state.counter + 1 })),
      on(decrement, (state) => ({ ...state, counter: state.counter - 1 })),
      on(reset, (state) => ({ ...state, counter: 0 })),
      on(set, (state, { value }) => ({ ...state, counter: value }))
    );
    
  3. Actualitzar Component:

    @Component({
      selector: 'app-counter',
      template: `
        <div>
          <h1>{{ counter$ | async }}</h1>
          <button (click)="increment()">Increment</button>
          <button (click)="decrement()">Decrement</button>
          <button (click)="reset()">Reset</button>
          <button (click)="setCounter(5)">Set to 5</button>
        </div>
      `,
    })
    export class CounterComponent {
      counter$: Observable<number>;
    
      constructor(private store: Store<AppState>) {
        this.counter$ = this.store.select(selectCounter);
      }
    
      increment() {
        this.store.dispatch(increment());
      }
    
      decrement() {
        this.store.dispatch(decrement());
      }
    
      reset() {
        this.store.dispatch(reset());
      }
    
      setCounter(value: number) {
        this.store.dispatch(set({ value }));
      }
    }
    

Resum

En aquest mòdul, hem après els conceptes bàsics de NgRx Store, com configurar-lo en una aplicació Angular, i com crear accions, reducers i selectors. També hem vist com integrar NgRx Store amb components Angular per gestionar l'estat de l'aplicació de manera eficient. Els exercicis pràctics proporcionats ajuden a reforçar aquests conceptes i a aplicar-los en situacions reals.

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