Fermer

novembre 1, 2024

Premiers pas avec l’API de ressources dans Angular

Premiers pas avec l’API de ressources dans Angular


Prenez une longueur d’avance sur l’API Resource, disponible très bientôt avec Angular 19 !

Angular 19 introduira une nouvelle API réactive appelée Resource API. L’objectif principal de l’API Resource est de charger les ressources, telles que :

  • Récupérer les données de l’API
  • Mettre à jour les données localement
  • Charger une ressource locale de manière asynchrone
  • Il ne doit pas être utilisé pour des mutations telles que les opérations POST.

Il doit principalement être utilisé pour charger les données de l’API en utilisant le protocole HTTP. Vous pouvez créer une ressource simple comme indiqué ci-dessous :

export class AppComponent {

  productResource = resource({
    loader: async () => {
      return Promise.resolve({ name: 'Book', price: 100 });
    }
  })

}

Par défaut, la fonction de chargement renvoie la promesse, et vous pouvez lire la valeur sur le modèle ci-dessous :

<h2>{{productResource.value()?.name}}</h2>

L’API Resource renvoie un WritableResource et possède des propriétés en lecture seule telles que :

  • Valeur
  • Statut
  • Erreur
  • est en cours de chargement

Tous sont des types de signaux, ce qui signifie que vous pouvez les suivre dans un effet.

constructor(){
    effect(()=>{
      console.log('Product Resource Data ', this.productResource.value());
      console.log('Product Resource Staus  ', this.productResource.status());
      console.log('Product Resource Error ', this.productResource.error());
      console.log('Product Resource is Loading  ', this.productResource.isLoading());
    })
  }

Angular imprime les valeurs comme ci-dessous :

Statistiques des ressources produit 2

Une fois Promise est résolu dans la fonction de chargement, il affiche :

Statistiques des ressources produit 4

Comme vous le voyez, la valeur Status est passée de 2 à 4. Le ResourceStatus est défini comme ci-dessous :

  • Inactif = 0
  • Erreur = 1
  • Chargement = 2
  • Rechargement = 3
  • Résolu = 4
  • Locale = 5

Dans la bibliothèque Angular, l’API Resource fonctionne comme défini ci-dessous :

  • Il construit une « Ressource » qui projette une requête réactive vers une opération asynchrone définie par une fonction de chargement.
  • Il expose le résultat de l’opération de chargement via des signaux.
  • La « Ressource » est destinée à l’opération de lecture, et non à l’opération effectuant la mutation.
  • Il annule tout chargement en cours lorsqu’un nouvel objet de requête devient disponible.

L’API Resource prend le type ResourceOptions comme paramètre d’entrée, avec les fonctions suivantes comme propriétés :

  1. Demande
  2. Chargeur
  3. Égal
  4. Injecteur

La fonction de requête détermine la requête à effectuer. Chaque fois que la demande change, le chargeur sera déclenché pour récupérer une nouvelle valeur et annuler toute opération de chargement en cours.

Comprenons la demande avec un exemple. Vous souhaitez récupérer un nouveau produit chaque fois qu’une valeur de signal change :

  id: WritableSignal<number> = signal(1);

  fetchnewProduct() {
    this.id.update(a => a + 1);
  }

Pour récupérer un nouveau produit à chaque fois que la valeur du signal d’identification est mise à jour, utilisez-le dans l’API de ressources comme ci-dessous :

productResource = resource({
    request: this.id,
    loader: async () => {
      let c = this.id();
      return Promise.resolve({ name: 'Book', price: 100 * c });
    }
  })

Comme l’API de ressources renvoie le WritableResourceAngular permet la mise à jour locale de la valeur de l’API Resource.

updateResource(): void {
    this.productResource.update((value: any) => {

      if (value.price == 500) {
        console.log('value if:', value);
        return { ...value, price: 1 };
      }
      console.log('value', value);
      return { ...value };
    })
  }

Un bouton peut déclencher la fonction en cliquant sur le modèle.

<button (click)="updateResource()">Update Resource Locally</button>

Travailler avec l’API de ressources

L’objectif principal de l’API Resource est de charger des données. Pour récupérer ces données, créons une interface pour le produit.

export interface Product {
    id: number, 
    name: string, 
    price: number 
}


Pour effectuer un appel API, créez une ressource et utilisez fetch dans le chargeur pour effectuer l’opération GET :

products?: Product[] = [];
  productApiResource = resource({
    loader: async () => {
      return fetch('http://localhost:3000/products').then(
        (res) => res.json() as Promise<Product[]>
      );
    },
  });

Vous pouvez utiliser le productApiResource sur le modèle pour lier les données à une table.

<table>
  <thead>
    <tr>
      <th>Id</th>
      <th>Name</th>
      <th>Price</th>
    </tr>
  </thead>
  <tbody>
    @for(p of productApiResource.value(); track p.id){
    <tr>
      <td>{{p.id}}</td>
      <td>{{p.name}}</td>
      <td>{{p.price}}</td>
    </tr>
    }
  </tbody>
</table>

Vous pouvez récupérer un produit spécifique en créant un signal pour productId. Le chargeur s’exécutera à chaque fois productId est mis à jour ou défini avec la nouvelle valeur.

productId: WritableSignal<number> = signal(1);
  productApiResource = resource({
    request: () => ({ id: this.productId() }),
    loader: async (param) => {
      const { id } = param.request as { id: number };
      let url = `http://localhost:3000/products?id=${id}`;
      return fetch(url).then((res) => res.json() as Promise<Product[]>);
    },
  });

Quand le productId modifications, l’API de ressources récupère automatiquement les données.

Gérer plusieurs demandes

Chaque fois que le productId changements, et s’il y a une demande de chevauchement, l’API de ressources effectue ces tâches :

  1. Il recharge les données en exécutant le chargeur.
  2. Il n’annule pas la requête en cours mais ignore son résultat.
  3. Il renvoie uniquement le résultat de la dernière requête.

Ainsi, pour annuler la demande précédente et en cours lorsque le productId changements, nous devons utiliser le abortSignal de l’API de ressources.

productId: WritableSignal<number> = signal(1);
  productApiResource = resource({
    request: () => ({ id: this.productId() }),
    loader: async (param) => {
      const { id } = param.request as { id: number };
      let url = `http://localhost:3000/products?id=${id}`;
      return fetch(url, { signal: param.abortSignal }).then((res) => res.json() as Promise<Product[]>);
    },
  });

Ici, le abortSignal est une API JavaScript prise en charge par tous les navigateurs et utilisée par l’API Fetch pour annuler la requête en cours. Alors évitez de confondre abortSignal avec quelque chose lié aux signaux angulaires.

La demande n’est pas définie

Le chargeur n’effectue pas l’appel API si la requête renvoie undefined. Ainsi, pour reporter la requête API dans la fonction Resource API Loader, retournez undefined de la demande.

  productApiResource = resource({
    request: () => (undefined),
    loader: async (param) => {
      const { id } = param.request as { id: number };
      let url = `http://localhost:3000/products?id=${id}`;
      return fetch(url, { signal: param.abortSignal }).then((res) => res.json() as Promise<Product[]>);
    },
  });

Le chargeur ci-dessus ne fera jamais d’appel API.

La demande est suivie et le chargeur n’est pas suivi

L’API Resource prend deux paramètres essentiels :

  1. Demande
  2. Chargeur

Le paramètre de requête est suivi, mais le chargeur n’est pas suivi.

Angular n’exécute pas à nouveau le chargeur si le signal utilisé à l’intérieur du chargeur est modifié. Cependant, puisque la requête est suivie, une modification du signal utilisé dans la requête permettra au chargeur d’être à nouveau exécuté.

La fonction du chargeur ne se réexécute pas automatiquement lorsqu’un signal à l’intérieur du chargeur change. La simple mise à jour d’un signal dans le chargeur ne déclenchera pas la réexécution du chargeur.

Cependant, Angular suit les signaux utilisés dans la requête. Ainsi, si un signal change dans la requête, Angular suit ce changement et réexécute le chargeur pour récupérer les données mises à jour. Cette approche permet de garantir que le chargeur ne se réexécute que lorsque cela est nécessaire, optimisant ainsi les performances en évitant les appels d’API inutiles.

Ainsi, le chargeur n’est pas suivi et une demande est suivie. Par exemple, lorsque le productid le signal change, le chargeur ne se réexécutera pas automatiquement et vous ne recevrez pas de données mises à jour.

productApiResource = resource({
    loader: async (param) => {
      let id  = this.productId();
      let url = `http://localhost:3000/products?id=${id}`;
      return fetch(url, { signal: param.abortSignal }).then(
        (res) => res.json() as Promise<Product[]>
      );
    },
  });

Résumé

Au moment d’écrire ces lignes, Angular 19 n’a pas encore été publié, l’API de ressources peut donc encore subir des modifications. L’API Resource simplifie le chargement des données dans une approche basée sur le signal et doit être utilisée spécifiquement pour le chargement des données, et non pour les mutations.

J’espère que vous trouverez cet article utile. Merci d’avoir lu!




Source link