Kodokon kodokon.com

Appeler une API : fetch, chargement et erreurs

Chargez des données distantes avec fetch dans un effet, en modélisant proprement les états de chargement et d'erreur.

10 min · 3 questions

Ouvrir cette leçon dans Kodokon

Une requête réseau met du temps et peut échouer : votre interface doit refléter ces réalités. La convention professionnelle consiste à suivre trois états distincts : les données reçues, un booléen de chargement et une éventuelle erreur. La requête part dans un useEffect, car contacter un serveur est un effet de bord.

JSX
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);

useEffect(() => {
  fetch("https://api.example.com/users")
    .then((res) => {
      if (!res.ok) throw new Error("HTTP " + res.status);
      return res.json();
    })
    .then((data) => setUsers(data))
    .catch((err) => setError(err.message))
    .finally(() => setLoading(false));
}, []);
Trois états pour une requête : données, chargement, erreur.

Au rendu, traitez les cas dans l'ordre : d'abord le chargement, puis l'erreur, enfin les données. Ces retours anticipés gardent le code lisible et garantissent que l'utilisateur voit toujours quelque chose de cohérent : un indicateur d'attente, un message d'échec ou la liste attendue.

JSX
if (loading) return <p>Chargement…</p>;
if (error) return <p>Erreur : {error}</p>;

return (
  <ul>
    {users.map((user) => (
      <li key={user.id}>{user.name}</li>
    ))}
  </ul>
);
Retours anticipés : un seul cas affiché à la fois.

Dernier piège : si une dépendance change (un userId par exemple), une nouvelle requête part alors que l'ancienne est peut-être encore en vol. Si l'ancienne répond en dernier, elle écraserait les données fraîches. La parade classique : un drapeau ignore remis à true par la fonction de nettoyage, pour jeter les réponses obsolètes.

JSX
useEffect(() => {
  let ignore = false;
  setLoading(true);

  fetch("/api/users/" + userId)
    .then((res) => res.json())
    .then((data) => {
      if (!ignore) setUser(data);
    })
    .finally(() => {
      if (!ignore) setLoading(false);
    });

  return () => {
    ignore = true;
  };
}, [userId]);
Chaque réponse périmée est ignorée grâce au drapeau.

Quiz de validation

Vérifiez que vous avez bien retenu les points clés de cette leçon.

  1. Pourquoi suivre trois états (données, chargement, erreur) pour une requête ?
    • Parce que fetch exige ces trois variables pour fonctionner
    • Pour que l'interface reflète chaque phase : attente, échec ou succès
    • Pour éviter que React ne relance la requête à chaque rendu
  2. Votre API répond avec un statut 500, mais le catch ne se déclenche pas. Pourquoi ?
    • fetch ne rejette la promesse qu'en cas de panne réseau, pas pour un statut d'erreur HTTP
    • Le catch ne fonctionne pas à l'intérieur d'un useEffect
    • Le serveur doit renvoyer un en-tête spécial pour déclencher le catch
  3. À quoi sert le drapeau ignore remis à true dans le nettoyage de l'effet ?
    • À annuler la requête HTTP en cours côté serveur
    • À empêcher React de relancer l'effet
    • À écarter la réponse d'une requête devenue obsolète