Maison >interface Web >js tutoriel >Le Signal Store de NGRX – détail des principaux concepts

Le Signal Store de NGRX – détail des principaux concepts

WBOY
WBOYoriginal
2024-07-23 15:00:551232parcourir

The Signal Store from NGRX - breakdown of the main concepts

Caractéristiques

  • basé sur le signal
  • fonctionnel et déclaratif
  • utilisé pour la gestion de l'état local ou global
  • extensible avec des fonctionnalités personnalisées

Comment se compare-t-il au magasin mondial NGRX ?

  • API plus légère et simplifiée
  • n'avez pas à vous soucier autant du flux de données
  • semble plus difficile à utiliser à mauvais escient, comme réutiliser des actions
  • plus facile à étendre

Le créateur de NGRX Signal Store, Marko Stanimirovic décrit ici NgRx SignalStore : examen approfondi de la gestion de l'état basée sur le signal dans Angular

Limites de la gestion d'état basée sur les classes :

  • Typage : Il n'est pas possible de définir des propriétés de classe dynamique ou des méthodes fortement typées
  • Tree-shaking : les méthodes de classe inutilisées ne seront pas supprimées du bundle final
  • Extensibilité : l'héritage multiple n'est pas pris en charge.
  • Modularité : le fractionnement des sélecteurs, des mises à jour et des effets en différentes classes est possible, mais n'est pas fourni immédiatement

Explorons l'API du magasin avec des exemples de code. Nous utiliserons un projet avec une liste de produits et de fonctionnalités de filtrage.

Création d'un SignalStore

  • Fonction signalStore qui renvoie un service injectable pouvant être injecté et fourni là où il est nécessaire de l'utiliser.
import { signalStore } from "@ngrx/signals";

export const ProductStore = signalStore( … );

État fournissant withState

Comme pour n'importe quel magasin NGRX jusqu'à présent, un état initial peut être fourni, en utilisant la fonction withState qui accepte les littéraux d'objet, les enregistrements ou les fonctions d'usine (pour créer un état initial dynamique) comme entrées.

import { signalStore, withState } from "@ngrx/signals";

const initialProductState: ProductState = { products: [] };

export const ProductStore = signalStore(
 withState(initialProductState);
);

État calculé avecComputed

  • construit au-dessus de la fonction calculée pour créer des états dérivés (état calculé) à partir du magasin
import { signalStore, withComputed, withState } from "@ngrx/signals";

export const ProductStore = signalStore(
 withState(initialProductState),
 withComputed(({products}) => ({
   averagePrice: computed(() => {
     const total = products().reduce((acc, p) => acc + p.price, 0);
     return total / products().length;
   })
 })),

Effectuer des opérations avec des méthodes

  • c'est le lieu où seront définies les opérations du magasin
  • il peut s'agir de méthodes permettant de mettre à jour la boutique ou d'effectuer certaines opérations en fonction de son état actuel
import { signalStore, withComputed, withState, withMethods } from "@ngrx/signals";

export const ProductStore = signalStore(
 withState(initialProductState),
 withComputed(({products}) => ({
   averagePrice: computed(() => {
     const total = products().reduce((acc, p) => acc + p.price, 0);
     return total / products().length;
   })
 })),


 // CRUD operations
 withMethods((store,
   productService = inject(ProductService),
 ) => ({
   loadProducts: () => {
     const products = toSignal(productService.loadProducts())
     patchState(store, { products: products() })
   },
   addProduct: (product: Product) => {
     patchState(store, { products: [...store.products(), product] });
   },
   // ...
 })),

withMethods & withComputed accède à une fonction d'usine et renvoie un dictionnaire de méthodes et de signaux calculés accessibles en utilisant le magasin. Ils s'exécutent également dans un contexte d'injection, ce qui permet de leur injecter des dépendances.

Accrochage avecCrochets

  • méthodes de cycle de vie du magasin, il a actuellement les méthodes onInit et onDestroy
import { withHooks } from "@ngrx/signals"; 

export const ProductStore = signalStore(
 withHooks((store) => ({
   onInit() {
     // Load products when the store is initialized
     store.loadProducts();
   },
 })),
);

Gestion des collections avecEntities

  • utilisez-le lorsque vous devez gérer des données telles que « Produits, utilisateurs, clients, etc. » où des opérations CRUD sont nécessaires pour cette fonctionnalité
  • il fournit un ensemble d'API pour gérer les collections, comme : addEntity, setEntity, remoteEntity.
export const ProductStoreWithEntities = signalStore(
 withEntities<Product>(),


 // CRUD operations
 withMethods((store,
   productService = inject(ProductService),
 ) => ({
   loadProducts: () => {
     const products = toSignal(productService.loadProducts())();
     patchState(store, setAllEntities(products || []));
   },
   updateProduct: (product: Product) => {
     productService.updateProduct(product);
     patchState(store, setEntity(product));
   },

 })),

Il est possible d'ajouter plusieurs fonctionnalités commençant par « avec » mais elles ne peuvent accéder qu'à ce qui a été défini avant elles.

Création de fonctionnalités personnalisées avec signalStoreFeature

signalStoreFeature - utilisé pour étendre les fonctionnalités du magasin.

Les magasins peuvent devenir complexes et difficiles à gérer pour les applications des grandes entreprises. Lors de l'écriture de fonctionnalités et de composants pour un projet, plus la répartition est précise et granulaire, plus il est facile de gérer, de maintenir le code et d'écrire des tests pour celui-ci.

Cependant, compte tenu de l'API fournie par SignalStore, le magasin peut devenir difficile à gérer à moins que le code ne soit divisé en conséquence. signalStoreFeature convient pour extraire la fonctionnalité spécifique d'une fonctionnalité (ou d'un composant) dans une fonction testable autonome qui peut potentiellement (et idéalement) être réutilisée dans d'autres magasins.

export const ProductStore = signalStore(
 // previous defined state and methods

 // Externalizing filtering options
 withFilteringOptions(),
);


export function withFilteringOptions() {
 return signalStoreFeature(
  // Filtering operations
 withMethods(() => ({
   getProductsBetweenPriceRange: (lowPrice: number, highPrice: number, products: Array<Product>, ) => {
     return products.filter(p => p.price >= lowPrice && p.price <= highPrice);
   },


   getProductsByCategory: (category: string, products: Array<Product>) => {
     return products.filter(p => p.category === category);
   },
 })),
 );
}

Maintenant, un exemple de signalStoreFeature qui montre la possibilité de réutiliser signalStoreFeature(s) dans plusieurs magasins.

importer { patchState, signalStoreFeature, withMethods } depuis "@ngrx/signals";

export function withCrudOperations() {
 return signalStoreFeature(
   withMethods((store) => ({
     load: (crudService: CrudOperations) => crudService.load(),
     update: (crudableObject: CRUD, crudService: CrudOperations) => {
       crudService.update(crudableObject);
       patchState(store, setEntity(crudableObject));
     },
   }),
 ));
}

export interface CrudOperations {
 load(): void;
 update(crudableObject: CRUD): void;
}

// Product & Customer services must extend the same interface.

export class ProductService implements CrudOperations {
 load(): void {
   console.log('load products');
 }
 update(): void {
   console.log('update products');
 }
}

export class CustomerService implements CrudOperations {
 load(): void {
   console.log('load customers');
 }
 update(): void {
   console.log('update customers');
 }
}

// and now let’s add this feature in our stores

export const ProductStore = signalStore(
 withCrudOperations(),
);


export const CustomerStore = signalStore(
 withCrudOperations(),
);

Package utilitaire NGRX Toolkit

Étant aussi simple à étendre, il existe déjà un package utilitaire appelé ngrx-toolkit destiné à ajouter des outils utiles aux Signal Stores.

Injection de SignalStore

{ provideIn: 'root' } ou dans le tableau fournisseurs d'un composant, d'un service, d'une directive, etc.

Signaux profonds

  • Propriétés d'état imbriquées lues comme des signaux, générées paresseusement à la demande

État du patch

  • API alternative pour définir et mettre à jour (de l'API de signal) pour mettre à jour l'état du magasin, il suffit de fournir les valeurs que nous voulons modifier

rxMéthode

  • Méthode utilitaire qui permet d'utiliser RxJS avec SignalStore ou signalState

Alternative plus légère avec SignalState

  • SignalState offre une alternative à la gestion de l'état basé sur le signal de manière concise et minimaliste.

Réflexions finales

Il reste à prouver sa fiabilité pour les applications plus importantes, en particulier lorsqu'il est appliqué en tant que magasin mondial.

Pour l'instant, je pense que c'est un excellent ajout à l'API Signal par défaut, ce qui en fait une bonne option pour gérer :

  • état au niveau du composant
  • État basé sur les fonctionnalités

Ressources supplémentaires :

https://www.stefanos-lignos.dev/posts/ngrx-signals-store
https://www.angulararchitects.io/blog/the-new-ngrx-signal-store-for-angular-2-1-flavors/ (groupe de 4 articles sur le sujet)
https://ngrx.io/guide/signals

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn