Maison > interface Web > js tutoriel > API Angular Resource() et rxResource() : ce que vous devez savoir

API Angular Resource() et rxResource() : ce que vous devez savoir

DDD
Libérer: 2025-01-04 06:52:43
original
474 Les gens l'ont consulté

Angular resource() and rxResource() APIs: what you need to know

La sortie de Angular v19, il y a quelques semaines seulement, marque une étape importante dans la révolution du signal au sein du framework, avec le Input, Modèle, Sortie et Signal RequêtesLes API sont désormais officiellement promues au statut stable.

Mais ce n'est pas tout ! Cette version majeure introduit également de nouveaux outils puissants conçus pour faire progresser encore la révolution du signal : la nouvelle API de ressources.

Comme son nom l'indique, cette nouvelle API de ressources est conçue pour simplifier le chargement des ressources asynchrones en exploitant toute la puissance des signaux !

IMPORTANT : au moment de la rédaction, la nouvelle API de ressources est encore expérimentale. Cela signifie qu'il peut changer avant de devenir stable, alors utilisez-le à vos propres risques. ?

Plongeons dans son fonctionnement et comment il simplifie la gestion des ressources asynchrones !


L'API des ressources

La plupart des API de signal sont synchrones, mais dans les applications du monde réel, il est essentiel de gérer des ressources asynchrones, telles que la récupération de données sur un serveur ou la gestion des interactions des utilisateurs en temps réel.

C'est là que la nouvelle API Resource entre en jeu.

En utilisant une Ressource, vous pouvez facilement consommer une ressource asynchrone via des signaux, vous permettant de gérer facilement la récupération de données, de gérer les états de chargement et de déclencher une nouvelle récupération chaque fois que les paramètres de signal associés changent.

fonction ressource( )

Le moyen le plus simple de créer une Ressource consiste à utiliser la fonction resource() :

import { resource, signal } from '@angular/core';

const RESOURCE_URL = 'https://jsonplaceholder.typicode.com/todos/';

private id = signal(1);

private myResource = resource({
    request: () => ({ id: this.id() }),
    loader: ({ request }) => fetch(RESOURCE_URL + request.id),
});
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Cette fonction accepte un objet de configuration ResourceOptions en entrée, vous permettant de spécifier les propriétés suivantes :

  • request : une fonction réactive qui détermine les paramètres utilisés pour effectuer la requête vers la ressource asynchrone ;
  • loader : une fonction de chargement qui renvoie une Promise de la valeur de la ressource, éventuellement basée sur les paramètres request fournis. Il s'agit de la seule propriété obligatoire de ResourceOptions;
  • equal : fonction d'égalité utilisée pour comparer la valeur de retour du loader ;
  • injecteur : remplace le Injecteur utilisé par l'instance Resource pour se détruire lorsque le composant ou le service parent est détruit.

Grâce à ces configurations, nous pouvons facilement définir une dépendance asynchrone qui sera toujours consommée efficacement et maintenue à jour.

Cycle de vie des ressources

Une fois qu'une Ressource est créée, la fonction loader est exécutée, puis la requête asynchrone résultante démarre :

import { resource, signal } from '@angular/core';

const RESOURCE_URL = 'https://jsonplaceholder.typicode.com/todos/';

private id = signal(1);

private myResource = resource({
    request: () => ({ id: this.id() }),
    loader: ({ request }) => fetch(RESOURCE_URL + request.id),
});
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Chaque fois qu'un signal indiquant que la fonction request dépend de changements, la fonction request s'exécute à nouveau, et si elle renvoie de nouveaux paramètres, la fonction loader est déclenchée pour récupérer la valeur de la ressource mise à jour :

import { resource, signal } from "@angular/core";

const RESOURCE_URL = "https://jsonplaceholder.typicode.com/todos/";

const id = signal(1);
const myResource = resource({
  request: () => ({ id: id() }),
  loader: ({ request }) => fetch(RESOURCE_URL + request.id)
});
console.log(myResource.status()); // Prints: 2 (which means "Loading")
Copier après la connexion
Copier après la connexion
Copier après la connexion

Si aucune fonction request n'est fournie, la fonction loader ne s'exécutera qu'une seule fois, à moins que la Resource ne soit rechargée à l'aide du reload méthode (plus ci-dessous).

Enfin, une fois le composant ou service parent détruit, la Ressource est également détruite sauf si un injecteur spécifique a été prévu.

Dans de tels cas, la Ressource restera active et ne sera détruite que lorsque l'injecteur fourni lui-même sera détruit.

Abandonner les requêtes avec abortSignal

Pour optimiser la récupération des données, une Ressource peut abandonner une requête en attente si le calcul request() change alors qu'une valeur précédente est toujours en cours de chargement.

Pour gérer cela, la fonction loader() fournit un abortSignal, que vous pouvez transmettre aux requêtes en cours, telles que fetch. La requête écoute le abortSignal et annule l'opération si elle est déclenchée, garantissant ainsi une gestion efficace des ressources et évitant les requêtes réseau inutiles :

import { resource, signal } from "@angular/core";

const RESOURCE_URL = "https://jsonplaceholder.typicode.com/todos/";

const id = signal(1);
const myResource = resource({
  request: () => ({ id: id() }),
  loader: ({ request }) => fetch(RESOURCE_URL + request.id)
});

console.log(myResource.status()); // Prints: 2 (which means "Loading")

// After the fetch resolves

console.log(myResource.status()); // Prints: 4 (which means "Resolved")
console.log(myResource.value()); // Prints: { "id": 1 , ... }

id.set(2); // Triggers a request, causing the loader function to run again
console.log(myResource.status()); // Prints: 2 (which means "Loading")

// After the fetch resolves

console.log(myResource.status()); // Prints: 4 (which means "Resolved")
console.log(myResource.value()); // Prints: { "id": 2 , ... }
Copier après la connexion
Copier après la connexion
Copier après la connexion

Sur cette base, il est recommandé d'utiliser l'API Resource principalement pour les requêtes GET, car elles peuvent généralement être annulées en toute sécurité sans causer de problèmes.

Pour les demandes POST ou UPDATE, l'annulation peut entraîner des effets secondaires involontaires, tels que des soumissions ou des mises à jour de données incomplètes. Cependant, si vous avez besoin de fonctionnalités similaires pour ces types de requêtes, vous pouvez utiliser la méthode effect() pour gérer les opérations en toute sécurité.


Comment consommer une ressource

L'API Resource fournit plusieurs propriétés de signal pour son état, que vous pouvez facilement utiliser directement au sein de vos composants ou services :

  • valeur : contient la valeur actuelle de la Ressource, ou non définie si aucune valeur n'est disponible. En tant que WritableSignal, il peut être mis à jour manuellement ;
  • statut : contient l'état actuel de la Ressource, indiquant ce que fait la Ressource et ce que l'on peut attendre de sa valeur ;
  • erreur : s'il est dans l'état d'erreur, il contient l'erreur la plus récente générée lors du chargement de la Ressource ;
  • isLoading : indique si la Ressource charge une nouvelle valeur ou recharge celle existante.

Voici un exemple de la façon de consommer une Ressource au sein d'un composant :

import { resource, signal } from '@angular/core';

const RESOURCE_URL = 'https://jsonplaceholder.typicode.com/todos/';

private id = signal(1);

private myResource = resource({
    request: () => ({ id: this.id() }),
    loader: ({ request }) => fetch(RESOURCE_URL + request.id),
});
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Dans cet exemple, la Resource est utilisée pour récupérer des données d'une API en fonction de la valeur du signal id, qui peut être incrémentée en cliquant sur un bouton.

Chaque fois que l'utilisateur clique sur le bouton, la valeur du signal id change, déclenchant la fonction loader pour récupérer un nouvel élément à partir de l'API distante.

L'interface utilisateur se met automatiquement à jour avec les données récupérées grâce aux propriétés des signaux exposées par l'API Resource.


Vérifier l'état d'une ressource

Comme mentionné précédemment, le signal status fournit des informations sur l'état actuel de la ressource à un moment donné.

Les valeurs possibles du signal status sont définies par l'énumération ResourceStatus. Voici un récapitulatif de ces statuts et de leurs valeurs correspondantes :

  • Idle = 0 : la Ressource n'a aucune requête valide et n'effectuera aucun chargement. value() est indéfini;
  • Erreur = 1 : le chargement a échoué avec une erreur. value() est indéfini;
  • Loading = 2 : la ressource est en train de charger une nouvelle valeur suite à un changement dans sa requête. value() est indéfini;
  • Reloading = 3 : la ressource recharge actuellement une nouvelle valeur pour la même requête. value() continuera à renvoyer la valeur précédemment récupérée jusqu'à ce que l'opération de rechargement soit terminée ;
  • Résolu = 4 : le chargement est terminé. value() contient la valeur renvoyée par le processus de récupération de données du chargeur ;
  • Local = 5 : la valeur a été définie localement via set() ou update(). value() contient la valeur attribuée manuellement.

Ces statuts permettent de suivre la progression de la Ressource et facilitent une meilleure gestion des opérations asynchrones dans votre application.

fonction hasValue( )

Compte tenu de la complexité de ces statuts, l'API Resource fournit une méthode hasValue(), qui renvoie un booléen basé sur le statut actuel.

Cela garantit des informations précises sur l'état de la Ressource, offrant un moyen plus fiable de gérer les opérations asynchrones sans compter sur la valeur, qui peut être non définie dans certains états.

import { resource, signal } from '@angular/core';

const RESOURCE_URL = 'https://jsonplaceholder.typicode.com/todos/';

private id = signal(1);

private myResource = resource({
    request: () => ({ id: this.id() }),
    loader: ({ request }) => fetch(RESOURCE_URL + request.id),
});
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Cette méthode est réactive, vous permettant de la consommer et de la suivre comme un signal.

Fonction isLoading( )

L'API Resource fournit également un signal isLoading, qui renvoie si la ressource est actuellement dans l'état Loading ou Reloading :

import { resource, signal } from "@angular/core";

const RESOURCE_URL = "https://jsonplaceholder.typicode.com/todos/";

const id = signal(1);
const myResource = resource({
  request: () => ({ id: id() }),
  loader: ({ request }) => fetch(RESOURCE_URL + request.id)
});
console.log(myResource.status()); // Prints: 2 (which means "Loading")
Copier après la connexion
Copier après la connexion
Copier après la connexion

Puisque isLoading est un signal calculé, il peut être suivi de manière réactive, vous permettant de surveiller l'état de chargement en temps réel à l'aide des API de signaux.


Valeur de la ressource en tant que WritableSignal

Le signal de valeur fourni par une Resource est un WritableSignal, qui permet de le mettre à jour manuellement à l'aide des set() et update( ) fonctions :

import { resource, signal } from "@angular/core";

const RESOURCE_URL = "https://jsonplaceholder.typicode.com/todos/";

const id = signal(1);
const myResource = resource({
  request: () => ({ id: id() }),
  loader: ({ request }) => fetch(RESOURCE_URL + request.id)
});

console.log(myResource.status()); // Prints: 2 (which means "Loading")

// After the fetch resolves

console.log(myResource.status()); // Prints: 4 (which means "Resolved")
console.log(myResource.value()); // Prints: { "id": 1 , ... }

id.set(2); // Triggers a request, causing the loader function to run again
console.log(myResource.status()); // Prints: 2 (which means "Loading")

// After the fetch resolves

console.log(myResource.status()); // Prints: 4 (which means "Resolved")
console.log(myResource.value()); // Prints: { "id": 2 , ... }
Copier après la connexion
Copier après la connexion
Copier après la connexion

Remarque : comme vous pouvez le voir, la mise à jour manuelle de la valeur du signal définira également l'état sur 5, ce qui signifie "Local ", pour indiquer que la valeur a été définie localement.

La valeur définie manuellement persistera jusqu'à ce qu'une nouvelle valeur soit définie ou qu'une nouvelle requête soit effectuée, qui la remplacera par une nouvelle valeur :

import { resource, signal } from "@angular/core";

const RESOURCE_URL = "https://jsonplaceholder.typicode.com/todos/";

const id = signal(1);
const myResource = resource({
  request: () => ({ id: id() }),
  loader: ({ request, abortSignal }) =>
    fetch(RESOURCE_URL + request.id, { signal: abortSignal })
});

console.log(myResource.status()); // Prints: 2 (which means "Loading")

// Triggers a new request, causing the previous fetch to be aborted
// Then the loader function to run again generating a new fetch request
id.set(2);

console.log(myResource.status()); // Prints: 2 (which means "Loading")
Copier après la connexion

Remarque : le signal value de l'Resource API utilise le même modèle de la nouvelle LinkedSignal API, mais n'utilise pas sous le capot. ?

Méthodes d'emballage pratiques

Pour simplifier l'utilisation du signal value, l'API Resource fournit des wrappers pratiques pour le set, la update et asReadonly méthodes.

La méthode asReadonly est particulièrement utile car elle renvoie une instance en lecture seule du signal value, permettant l'accès uniquement en lecture et empêchant toute modification accidentelle.

Vous pouvez utiliser cette approche pour créer des services qui gèrent et suivent les modifications apportées aux valeurs des ressources en exportant une instance en lecture seule de la valeur :

import { Component, resource, signal } from '@angular/core';

const BASE_URL = 'https://jsonplaceholder.typicode.com/todos/';

@Component({
  selector: 'my-component',
  template: `
    @if (myResource.value()) {
      {{ myResource.value().title }}
    }

    <button (click)="fetchNext()">Fetch next item</button>
  `
})
export class MyComponent {
  private id = signal(1);

  protected myResource = resource({
    request: () => ({ id: this.id() }),
    loader: ({ request }) =>
      fetch(BASE_URL + request.id).then((response) => response.json()),
  });

  protected fetchNext(): void {
    this.id.update((id) => id + 1);
  }
}
Copier après la connexion

Cela empêchera les consommateurs de modifier la valeur, réduisant ainsi le risque de changements involontaires et améliorant la cohérence dans la gestion des données complexes.


Recharger ou détruire une ressource

Lorsque vous travaillez avec des ressources asynchrones, vous pouvez être confronté à des scénarios dans lesquels l'actualisation des données ou la destruction de la Ressource devient nécessaire.

Pour gérer ces scénarios, l'API Resource propose deux méthodes dédiées qui offrent des solutions efficaces pour gérer ces actions.

fonction recharger( )

La méthode reload() demande à la Ressource de réexécuter la requête asynchrone, en s'assurant qu'elle récupère les données les plus à jour :

import { resource, signal } from '@angular/core';

const RESOURCE_URL = 'https://jsonplaceholder.typicode.com/todos/';

private id = signal(1);

private myResource = resource({
    request: () => ({ id: this.id() }),
    loader: ({ request }) => fetch(RESOURCE_URL + request.id),
});
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

La méthode reload() renvoie true si un rechargement est lancé avec succès.

Si un rechargement ne peut pas être effectué, soit parce qu'il est inutile, comme lorsque le statut est déjà Chargement ou Rechargement, soit non pris en charge, comme lorsque le statut est Idle, la méthode renvoie false.

fonction détruire( )

La méthode destroy() détruit manuellement la Ressource, détruisant tout effet() utilisé pour suivre les modifications de la demande, annulant toutes les demandes en attente et définissant le statut sur Idle tout en réinitialisant la valeur à non défini :

import { resource, signal } from "@angular/core";

const RESOURCE_URL = "https://jsonplaceholder.typicode.com/todos/";

const id = signal(1);
const myResource = resource({
  request: () => ({ id: id() }),
  loader: ({ request }) => fetch(RESOURCE_URL + request.id)
});
console.log(myResource.status()); // Prints: 2 (which means "Loading")
Copier après la connexion
Copier après la connexion
Copier après la connexion

Après la destruction d'une Ressource, elle ne répondra plus aux demandes de modifications ou aux opérations reload().

Remarque : à ce stade, tant que le signal valeur reste inscriptible, la Ressource perdra son objectif et ne remplira plus sa fonction, devenant inutile . ?


Fonction rxResource( )

Comme presque toutes les API basées sur les signaux introduites jusqu'à présent, l'API Resource offre également un utilitaire d'interopérabilité pour une intégration transparente avec RxJS.

Au lieu d'utiliser la méthode resource() pour créer une Resource basée sur la promesse, vous pouvez utiliser la méthode rxResource() pour utiliser Observables :

import { resource, signal } from "@angular/core";

const RESOURCE_URL = "https://jsonplaceholder.typicode.com/todos/";

const id = signal(1);
const myResource = resource({
  request: () => ({ id: id() }),
  loader: ({ request }) => fetch(RESOURCE_URL + request.id)
});

console.log(myResource.status()); // Prints: 2 (which means "Loading")

// After the fetch resolves

console.log(myResource.status()); // Prints: 4 (which means "Resolved")
console.log(myResource.value()); // Prints: { "id": 1 , ... }

id.set(2); // Triggers a request, causing the loader function to run again
console.log(myResource.status()); // Prints: 2 (which means "Loading")

// After the fetch resolves

console.log(myResource.status()); // Prints: 4 (which means "Resolved")
console.log(myResource.value()); // Prints: { "id": 2 , ... }
Copier après la connexion
Copier après la connexion
Copier après la connexion

Remarque : la méthode rxResource() est en fait exposée par le package rxjs-interop.

Le Observable produit par la fonction loader() ne considérera que la première valeur émise, ignorant les émissions suivantes.


Merci d'avoir lu jusqu'à présent ?

Merci à tous de m'avoir suivi tout au long de cette merveilleuse année 2024. ??

Cela a été une année pleine de défis, mais aussi très enrichissante. J'ai de grands projets pour 2025 et j'ai hâte de commencer à y travailler. ?

J'aimerais avoir vos commentaires, alors n'hésitez pas à laisser un commentaire, un j'aime ou un suivre. ?

Ensuite, si vous l'avez vraiment aimé, partagez-le avec votre communauté, vos techniciens et qui vous voulez. Et n'oubliez pas de me suivre sur LinkedIn. ??

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!

source:dev.to
Déclaration de ce site Web
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
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal