Server State

TanStack Query

TanStack Query est la couche de récupération de données manquante pour React. Il transforme les données serveur en un cache dont le chargement, les erreurs, le rafraîchissement et l'invalidation sont gérés pour vous.

intermediate14 min readUpdated 15 sept. 2026
usePosts.ts
tsx
// usePosts.ts
import { useQuery } from "@tanstack/react-query";

async function fetchPosts() {
  const res = await fetch("/api/posts");
  if (!res.ok) throw new Error("Failed to fetch posts");
  return res.json();
}

export function usePosts() {
  return useQuery({
    queryKey: ["posts"],
    queryFn: fetchPosts,
  });
}
Anciennement
React Query
Frameworks
React, Vue, Svelte, Solid
Lecture avec
useQuery
Écriture avec
useMutation
Clé de cache
queryKey
Devtools
Panneau dédié

Pourquoi c'est important

Pourquoi le server state a besoin de son propre outil

Un vrai cache pour les données serveur

Les requêtes sont mises en cache, dédupliquées et partagées entre les composants, ainsi la même donnée n'est récupérée qu'une seule fois.

Chargement et erreurs inclus

Chaque requête expose son statut, le chargement, l'erreur et les données, vous évitant ainsi d'écrire manuellement ces indicateurs.

Fraîcheur par politique

Le stale time, le refetch au focus et les mises à jour en arrière-plan maintiennent les données à jour sans effort manuel constant.

Le tableau complet

Les trois piliers de TanStack Query

Un cache indexé par requête, une fonction de requête qui récupère les données, et une invalidation qui garantit la fiabilité du cache.

Queries

Lecture

Une query key associée à une fonction de récupération décrit une donnée serveur et son entrée dans le cache.

Mutations

Écriture

useMutation gère les requêtes de création, mise à jour et suppression, et peut mettre à jour le cache en cas de succès.

Invalidation

Sync

Marque les données mises en cache comme obsolètes pour forcer leur récupération, gardant l'UI cohérente après un changement.

TanStack Query en un coup d'œil

Le cœur de TanStack Query

useQuery

S'abonner à une donnée serveur mise en cache via sa clé.

useMutation

Envoyer des requêtes de création, mise à jour et suppression avec gestion des états de chargement et d'erreur.

queryKey

L'identifiant d'une entrée de cache, utilisé pour la lire, la mettre à jour et l'invalider.

staleTime

Durée pendant laquelle une donnée est considérée comme fraîche avant un rafraîchissement en arrière-plan.

Invalidation

Marquer des requêtes comme obsolètes pour qu'elles se rafraîchissent si nécessaire.

Devtools

Inspecter chaque requête, son état et le cache dans un panneau dédié.

Un bref aperçu

L'essor de la gestion du server state

  1. 2019

    Sortie de React Query

    Une petite bibliothèque apporte la mise en cache et la gestion du server state à la récupération de données dans React.

    19
  2. 2021

    React Query 3

    Une adoption plus large et une API mature en font un standard courant.

    21
  3. 2022

    TanStack Query

    La bibliothèque est renommée et étendue à Vue, Svelte et Solid.

    22
  4. 2023

    TanStack Query 5

    Une API simplifiée, une meilleure inférence TypeScript et un bundle plus léger.

    23
  5. Aujourd'hui

    Le standard pour le server state

    Une couche largement utilisée qui s'associe à n'importe quelle bibliothèque de client state.

    Aujourd'hui

Le guide complet

TanStack Query: Tout ce que vous devez savoir

Qu’est-ce que TanStack Query ?

TanStack Query, anciennement React Query, est une bibliothèque de gestion d’état serveur (server-state management). Elle part du principe que les données récupérées via une API sont fondamentalement différentes de l’état que vous conservez dans useState. Les données serveur sont partagées, mises en cache, peuvent devenir obsolètes et doivent être récupérées à nouveau. Gérer cela avec des effets et des drapeaux (flags) est fastidieux et source de bugs.

TanStack Query offre aux données serveur un cache approprié. Vous décrivez comment récupérer une donnée et vous lui attribuez une clé ; la bibliothèque s’occupe ensuite du caching, de la déduplication, des états de chargement et d’erreur, du rafraîchissement en arrière-plan et de l’invalidation. C’est la couche de données manquante pour React, et elle s’intègre parfaitement avec n’importe quelle bibliothèque de gestion d’état client.

Requêtes

Une requête est définie par une clé et une fonction de requête. La clé identifie l’entrée dans le cache ; la fonction récupère les données.

// api.ts
async function fetchPost(id: string) {
  const res = await fetch(`/api/posts/${id}`);
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  return res.json();
}
// Post.tsx
import { useQuery } from "@tanstack/react-query";

export function Post({ id }: { id: string }) {
  const { data, isLoading, isError, error } = useQuery({
    queryKey: ["post", id],
    queryFn: () => fetchPost(id),
  });

  if (isLoading) return <p>Loading…</p>;
  if (isError) return <p>Error: {error.message}</p>;

  return <article>{data.title}</article>;
}

Chaque composant utilisant la même clé partage la même entrée de cache, ainsi, le montage du composant deux fois ne déclenche qu’un seul appel. Les indicateurs de statut sont fournis, vous n’avez donc jamais besoin de les écrire vous-même.

Clés de requête et cache

La clé représente l’identité de l’entrée du cache et doit inclure toutes les variables dont dépend la récupération des données.

// keys.ts
useQuery({ queryKey: ["posts"], queryFn: fetchPosts });
useQuery({ queryKey: ["post", id], queryFn: () => fetchPost(id) });
useQuery({
  queryKey: ["posts", { page, status }],
  queryFn: () => fetchPosts({ page, status }),
});

Comme les clés sont des tableaux, vous pouvez invalider toute une famille de données à l’aide d’un préfixe. L’invalidation de ["posts"] invalide également ["posts", { page: 1 }], ce qui rend les mises à jour du cache prévisibles.

Fraîcheur et rafraîchissement des données

Deux options contrôlent le moment où les données sont récupérées à nouveau.

// freshness.ts
useQuery({
  queryKey: ["posts"],
  queryFn: fetchPosts,
  staleTime: 60_000, // fresh for one minute
  gcTime: 5 * 60_000, // keep unused data for five minutes
});

staleTime définit la durée pendant laquelle les données sont considérées comme fraîches ; tant qu’elles sont fraîches, aucun rafraîchissement en arrière-plan n’a lieu. gcTime définit la durée pendant laquelle une entrée inutilisée reste en mémoire avant d’être supprimée par le garbage collector. Par défaut, les requêtes se rafraîchissent lors du montage, lors du focus de la fenêtre et lors de la reconnexion, ce qui permet de maintenir l’UI à jour sans aucune intervention manuelle.

Mutations

useMutation gère les écritures : la création, la mise à jour et la suppression.

// AddPost.tsx
import { useMutation, useQueryClient } from "@tanstack/react-query";

export function AddPost() {
  const queryClient = useQueryClient();

  const mutation = useMutation({
    mutationFn: (title: string) =>
      fetch("/api/posts", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ title }),
      }).then((r) => r.json()),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ["posts"] });
    },
  });

  return (
    <button
      onClick={() => mutation.mutate("New post")}
      disabled={mutation.isPending}
    >
      {mutation.isPending ? "Saving…" : "Add post"}
    </button>
  );
}

Après une mutation réussie, l’invalidation des requêtes affectées indique à chaque consommateur de refaire l’appel (refetch). Cela permet de garder le serveur comme source de vérité et d’éviter toute manipulation manuelle du cache.

Mises à jour optimistes

Pour les actions qui doivent paraître instantanées, mettez à jour le cache avant que le serveur ne réponde et annulez les modifications en cas d’échec.

// optimistic.ts
useMutation({
  mutationFn: toggleLike,
  onMutate: async (postId) => {
    await queryClient.cancelQueries({ queryKey: ["post", postId] });
    const previous = queryClient.getQueryData(["post", postId]);

    queryClient.setQueryData(["post", postId], (old) => ({
      ...old,
      likes: old.likes + 1,
    }));

    return { previous };
  },
  onError: (_err, postId, context) => {
    queryClient.setQueryData(["post", postId], context.previous);
  },
  onSettled: (_data, _err, postId) => {
    queryClient.invalidateQueries({ queryKey: ["post", postId] });
  },
});

onMutate applique la modification optimiste et enregistre l’ancienne valeur, onError effectue le rollback, et onSettled relance la récupération des données pour se synchroniser avec le serveur.

Pagination et requêtes infinies

TanStack Query offre un support natif pour les données paginées et infinies. useQuery avec une option keepPreviousData rend les transitions entre les pages fluides, et useInfiniteQuery gère les listes basées sur des curseurs grâce à une fonction fetchNextPage. Comme chaque page fait partie du cache, la navigation avant et arrière est instantanée.

État serveur versus état client

C’est cette distinction qui permet de vraiment comprendre l’intérêt de TanStack Query :

  • L’état serveur appartient au serveur, il est partagé, asynchrone et peut devenir obsolète. Utilisez TanStack Query.
  • L’état client appartient au navigateur, il est synchrone et local. Utilisez useState, Context, Zustand ou Redux.

Mélanger les deux dans un seul store est source de nombreuses complexités. Les séparer — TanStack Query pour les données, et un petit store pour l’état de l’UI — permet de garder chaque partie simple.

Bonnes pratiques

  • Incluez chaque variable dans la query key.
  • Définissez staleTime délibérément ; la valeur par défaut de zéro déclenche des refetchs très fréquents.
  • Utilisez des mutations accompagnées d’une invalidation plutôt que de mettre à jour manuellement le cache partout.
  • Gardez vos fonctions de requête courtes et colocalisées avec la requête.
  • Ajoutez des mises à jour optimistes uniquement là où un retour instantané est essentiel.
  • Utilisez les devtools pour inspecter l’état du cache pendant le développement.
  • Gardez l’état du serveur dans TanStack Query et l’état client ailleurs.

Erreurs courantes

  • Utiliser la même clé pour différentes entrées, ce qui entraîne l’affichage de données obsolètes ou incorrectes.
  • Laisser staleTime à zéro, déclenchant ainsi des refetches constants.
  • Dupliquer les données du serveur dans un store global.
  • Oublier d’invalider le cache après une mutation, affichant ainsi des données périmées.
  • Écrire des mises à jour optimistes (optimistic updates) sans prévoir de mécanisme de rollback.
  • Traiter les fonctions de requête comme des composants et appeler des hooks à l’intérieur de celles-ci.

Et après ?

TanStack Query est la méthode standard pour gérer les données serveur dans les applications modernes. Associez-le à l’ Fetch API pour la couche de requêtes, à un store client comme Zustand pour l’état de l’UI, et à Redux Toolkit si vous avez besoin d’un état global strict. Pour Vue, Pinia gère l’état client tandis que TanStack Query s’occupe de la partie serveur.

Récupération de données

useQuery met en cache, déduplique et expose l'état. La version avec useEffect récupère les données à chaque montage et nécessite des indicateurs manuels.

Préférer
const { data, isLoading, error } = useQuery({
  queryKey: ["posts"],
  queryFn: fetchPosts,
});
Éviter
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
  fetch("/api/posts")
    .then((r) => r.json())
    .then(setData)
    .finally(() => setLoading(false));
}, []);

Maintien de la fraîcheur des données

Invalidez la requête par sa clé après une mutation pour que chaque consommateur se rafraîchisse. Pas de manipulation manuelle du cache.

Préférer
const queryClient = useQueryClient();

const mutation = useMutation({
  mutationFn: addPost,
  onSuccess: () => {
    queryClient.invalidateQueries({
      queryKey: ["posts"],
    });
  },
});
Éviter
// refetching by hand in
// every component that
// happens to show posts

FAQ

Foire aux questions

Keep learning

Related topics from the roadmap.

$ commencer à apprendre

Prêt à apprendre TanStack Query ?

Notre tutoriel interactif vous guide à travers TanStack Query pas à pas — avec des quiz et du vrai code que vous pouvez exécuter dans le navigateur.