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:
Configuració Bàsica
-
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; }
-
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, });
-
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... );
-
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
- Crea una acció per afegir un llibre.
- Modifica el reductor per gestionar l'acció d'afegir un llibre.
- Actualitza el component per permetre afegir un llibre.
Exercici 2: Actualitzar un Llibre
- Crea una acció per actualitzar un llibre.
- Modifica el reductor per gestionar l'acció d'actualitzar un llibre.
- Actualitza el component per permetre actualitzar un llibre.
Exercici 3: Eliminar un Llibre
- Crea una acció per eliminar un llibre.
- Modifica el reductor per gestionar l'acció d'eliminar un llibre.
- 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
- Què és Angular?
- Configuració de l'entorn de desenvolupament
- Arquitectura d'Angular
- Primera aplicació Angular
Mòdul 2: Components d'Angular
- Comprendre els components
- Crear components
- Plantilles de components
- Estils de components
- Interacció de components
Mòdul 3: Enllaç de dades i directives
- Interpolació i enllaç de propietats
- Enllaç d'esdeveniments
- Enllaç de dades bidireccional
- Directives integrades
- Directives personalitzades
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
- Introducció al client HTTP
- Fer sol·licituds HTTP
- Gestionar respostes HTTP
- Utilitzar observables
- Gestió d'errors
Mòdul 8: Gestió d'estat
- Introducció a la gestió d'estat
- Utilitzar serveis per a la gestió d'estat
- NgRx Store
- NgRx Effects
- NgRx Entity
Mòdul 9: Proves a Angular
- Proves unitàries
- Proves de components
- Proves de serveis
- Proves de cap a cap
- Simulació de dependències
Mòdul 10: Conceptes avançats d'Angular
- Angular Universal
- Optimització del rendiment
- Internacionalització (i18n)
- Tubs personalitzats
- Animacions d'Angular