NgRx Entity és una biblioteca que forma part de l'ecosistema NgRx i està dissenyada per ajudar a gestionar col·leccions d'entitats en aplicacions Angular. Proporciona eines per simplificar operacions comunes com la selecció, actualització i eliminació d'entitats, així com la gestió de l'estat de càrrega.

Objectius del Tema

  • Comprendre què és NgRx Entity i per què és útil.
  • Aprendre a configurar NgRx Entity en una aplicació Angular.
  • Veure exemples pràctics d'ús de NgRx Entity per gestionar col·leccions d'entitats.
  • Realitzar exercicis pràctics per reforçar els conceptes apresos.

Què és NgRx Entity?

NgRx Entity proporciona una sèrie de funcions i estructures de dades per gestionar col·leccions d'entitats de manera eficient. Les seves principals característiques inclouen:

  • Normalització de dades: Emmagatzema les entitats en un format normalitzat per facilitar l'accés i la manipulació.
  • Selectors: Proporciona selectors predefinits per accedir a les entitats i als seus estats.
  • Reductors: Simplifica la creació de reductors per gestionar operacions comunes com l'addició, actualització i eliminació d'entitats.

Configuració de NgRx Entity

Instal·lació

Per començar a utilitzar NgRx Entity, primer cal instal·lar la biblioteca:

npm install @ngrx/entity

Configuració Bàsica

  1. Definir el Model d'Entitat: Primer, definim el model de l'entitat que volem gestionar. Per exemple, si estem gestionant una col·lecció de llibres:

    export interface Book {
      id: string;
      title: string;
      author: string;
    }
    
  2. Crear l'Adapter d'Entitat: Utilitzem createEntityAdapter per crear un adaptador per a la nostra entitat.

    import { createEntityAdapter, EntityAdapter, EntityState } from '@ngrx/entity';
    
    export interface BookState extends EntityState<Book> {
      // Podem afegir altres propietats d'estat aquí
      selectedBookId: string | null;
    }
    
    export const adapter: EntityAdapter<Book> = createEntityAdapter<Book>();
    
    export const initialState: BookState = adapter.getInitialState({
      // Valors inicials per a altres propietats d'estat
      selectedBookId: null,
    });
    
  3. Crear el Reductor: Utilitzem les funcions de l'adaptador per gestionar les operacions sobre les entitats.

    import { createReducer, on } from '@ngrx/store';
    import { Book } from './book.model';
    import { adapter, initialState, BookState } from './book.state';
    import * as BookActions from './book.actions';
    
    export const bookReducer = createReducer(
      initialState,
      on(BookActions.addBook, (state, { book }) => {
        return adapter.addOne(book, state);
      }),
      on(BookActions.updateBook, (state, { update }) => {
        return adapter.updateOne(update, state);
      }),
      on(BookActions.deleteBook, (state, { id }) => {
        return adapter.removeOne(id, state);
      }),
      // Altres accions...
    );
    
  4. Selectors: NgRx Entity proporciona selectors predefinits per accedir a les entitats i als seus estats.

    import { createFeatureSelector, createSelector } from '@ngrx/store';
    import { adapter, BookState } from './book.state';
    
    export const selectBookState = createFeatureSelector<BookState>('books');
    
    const { selectIds, selectEntities, selectAll, selectTotal } = adapter.getSelectors();
    
    export const selectBookIds = createSelector(selectBookState, selectIds);
    export const selectBookEntities = createSelector(selectBookState, selectEntities);
    export const selectAllBooks = createSelector(selectBookState, selectAll);
    export const selectBookTotal = createSelector(selectBookState, selectTotal);
    

Exemple Pràctic

Accions

Definim les accions per gestionar les operacions sobre els llibres:

import { createAction, props } from '@ngrx/store';
import { Book } from './book.model';
import { Update } from '@ngrx/entity';

export const addBook = createAction(
  '[Book List] Add Book',
  props<{ book: Book }>()
);

export const updateBook = createAction(
  '[Book List] Update Book',
  props<{ update: Update<Book> }>()
);

export const deleteBook = createAction(
  '[Book List] Delete Book',
  props<{ id: string }>()
);

Component

Un component que utilitza NgRx Entity per gestionar una col·lecció de llibres:

import { Component } from '@angular/core';
import { Store } from '@ngrx/store';
import { Observable } from 'rxjs';
import { Book } from './book.model';
import { selectAllBooks } from './book.selectors';
import * as BookActions from './book.actions';

@Component({
  selector: 'app-book-list',
  template: `
    <div *ngFor="let book of books$ | async">
      {{ book.title }} by {{ book.author }}
      <button (click)="deleteBook(book.id)">Delete</button>
    </div>
  `
})
export class BookListComponent {
  books$: Observable<Book[]>;

  constructor(private store: Store) {
    this.books$ = this.store.select(selectAllBooks);
  }

  deleteBook(id: string) {
    this.store.dispatch(BookActions.deleteBook({ id }));
  }
}

Exercicis Pràctics

Exercici 1: Afegir un Llibre

  1. Crea una acció per afegir un llibre.
  2. Modifica el reductor per gestionar l'acció d'afegir un llibre.
  3. Actualitza el component per permetre afegir un llibre.

Exercici 2: Actualitzar un Llibre

  1. Crea una acció per actualitzar un llibre.
  2. Modifica el reductor per gestionar l'acció d'actualitzar un llibre.
  3. Actualitza el component per permetre actualitzar un llibre.

Exercici 3: Eliminar un Llibre

  1. Crea una acció per eliminar un llibre.
  2. Modifica el reductor per gestionar l'acció d'eliminar un llibre.
  3. Actualitza el component per permetre eliminar un llibre.

Solucions

Solució Exercici 1

// book.actions.ts
export const addBook = createAction(
  '[Book List] Add Book',
  props<{ book: Book }>()
);

// book.reducer.ts
on(BookActions.addBook, (state, { book }) => {
  return adapter.addOne(book, state);
});

// book-list.component.ts
addBook(book: Book) {
  this.store.dispatch(BookActions.addBook({ book }));
}

Solució Exercici 2

// book.actions.ts
export const updateBook = createAction(
  '[Book List] Update Book',
  props<{ update: Update<Book> }>()
);

// book.reducer.ts
on(BookActions.updateBook, (state, { update }) => {
  return adapter.updateOne(update, state);
});

// book-list.component.ts
updateBook(update: Update<Book>) {
  this.store.dispatch(BookActions.updateBook({ update }));
}

Solució Exercici 3

// book.actions.ts
export const deleteBook = createAction(
  '[Book List] Delete Book',
  props<{ id: string }>()
);

// book.reducer.ts
on(BookActions.deleteBook, (state, { id }) => {
  return adapter.removeOne(id, state);
});

// book-list.component.ts
deleteBook(id: string) {
  this.store.dispatch(BookActions.deleteBook({ id }));
}

Conclusió

NgRx Entity simplifica la gestió de col·leccions d'entitats en aplicacions Angular, proporcionant eines per normalitzar dades, crear selectors i gestionar operacions comunes. Amb aquesta eina, podem escriure codi més net i mantenible, millorant l'eficiència del desenvolupament.

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