React Query et Redux : Repenser l’état serveur dans les applications volumineuses
Découvrez pourquoi une application de chat en production a utilisé TanStack Query plutôt que Redux pour gérer les données serveur, et où Redux occupe encore une place dans l’architecture React moderne.
Imaginez un développeur qui passe de projets plus petits à une entreprise axée sur des produits, désireux de voir enfin comment sont réellement construits des logiciels à grande échelle et de qualité professionnelle. Après des années passées à travailler sur des applications frontend, rejoindre une équipe chargée de logiciels utilisés par des millions de personnes change la manière dont on évalue du code.
On cesse de se demander simplement : "Cette fonctionnalité marche-t-elle ?"
On commence plutôt à se demander :
Comment cette architecture résiste-t-elle à des millions d’utilisateurs ? Comment l’état est-il synchronisé dans toute l’application ? Que se passe-t-il lorsque dix composants différents ont tous besoin de la même donnée ? Comment les ingénieurs maintiennent-ils une telle base de code à jour au fur et à mesure que le produit se développe ?
Imaginons maintenant que ce développeur soit affecté à l’un des modules clés du produit : une application de messagerie, similaire par son concept à Slack.
Ce n’est pas une fonctionnalité secondaire cachée dans un coin de l’application.
L’expérience de chat occupe le cœur du produit, servant des millions d’utilisateurs et étant étroitement liée aux flux de travail commerciaux essentiels, aux expériences génératrices de revenus ainsi qu’aux clients d’entreprise les plus importants de l’entreprise.
Il est donc logique que, en examinant pour la première fois le code source, ce développeur ait eu des attentes assez prévisibles.
Une application de chat à cette échelle doit inévitablement gérer un volume énorme d’informations que de nombreux écrans doivent partager : les threads et leurs messages, le nombre de messages non lus, les participants à une conversation, la navigation dans l’historique, les modifications et autres opérations d’écriture, les indicateurs de chargement en cours, ainsi que les mises à jour en temps réel.
Avec tout cela, on s’attendrait à trouver les éléments habituels dans un grand codebase React :
Redux, Zustand, ou au moins une forme de gestion d’état global.
Mais après avoir examiné le code, on ne trouve aucune boutique d’état.
Aucune configuration Redux.
Aucun Zustand.
Aucun objet Context étendu contenant les données partagées de l’application.
D’un premier coup d’œil, on pourrait facilement penser qu’il s’agit simplement d’une omission lors de l’exploration du dépôt.
Cependant, en creusant davantage, on découvre ce qui anime réellement la couche de données partagées.
TanStack Query.
C’est une découverte vraiment surprenante si votre modèle mental de cette bibliothèque est limité.
Beaucoup de développeurs considèrent React Query principalement comme un outil pour récupérer des données API, mettre en cache les réponses, suivre l’état de chargement et refaire la requête lorsque quelque chose change.
Cependant, dans cette application de niveau professionnel servant des millions d’utilisateurs, le cache de requêtes faisait bien plus que cela. Il fonctionnait comme le répertoire partagé pour toutes les données appartenant aux serveurs dans l’ensemble de l’application.
Cette observation remet en question une hypothèse longtemps admise concernant l’architecture frontend.
Peut-être que la bonne question n’est pas :
"Pourquoi n’y a-t-il pas de store Redux ici ?"
Peut-être devrait-elle être :
"Pourquoi les données appartenant aux serveurs auraient-elles besoin de se trouver dans Redux en premier lieu ?"
Cette question ouvre la voie à une discussion bien plus approfondie sur la manière dont nous modélisons l’état dans les applications React, et sur le fait que, dans de nombreux systèmes du monde réel, TanStack Query peut silencieusement éliminer une part surprenante de l’infrastructure d’état global que les équipes ont historiquement construite manuellement.
De Redux à React Query
Il y a eu une époque où intégrer une appel API dans une application React semblait être une tâche simple.
Puis Redux est apparu sur la scène.
L’appel API lui-même est resté simple. Tout ce qui l’entourait est devenu compliqué.
On définissait une action.
On écrivait un réducteur.
On ajoutait des indicateurs de chargement et d’erreur.
On envoyait l’action.
On enregistrait la réponse dans le store.
On écrivait un sélecteur pour la lire à nouveau.
On connectait le composant à tout cela.
Puis, des semaines ou des mois plus tard, quelqu’un demandait inévitablement :
« Pourquoi ces données ont-elles l’air obsolètes ? »
Et la solution consistait généralement en une autre action afin de forcer un nouveau chargement.
Après avoir traversé ce cycle à plusieurs reprises, un schéma gênant devient évident :
Les outils de gestion de l’état global étaient fréquemment utilisés pour gérer quelque chose qui n’était jamais vraiment une question d’état côté client à l’origine.
Le backend était le véritable propriétaire des données.
Le frontend ne faisait que les consommer.
Cette distinction explique en grande partie pourquoi TanStack Query est devenu une alternative intéressante dans les applications React modernes.
D’abord, qu’est-ce exactement React Query ?
TanStack Query, anciennement appelé React Query, n’est pas un substitut à useState, Redux ou Zustand.
Sa responsabilité principale est de gérer l’état serveur — des données provenant en dehors de votre application React qui doivent être récupérées, mises en cache, synchronisées, mises à jour et finalement considérées comme obsolètes.
React Query ne se limite pas à envoyer une requête et à stocker la réponse dans l’état local d’un composant.
La documentation officielle de TanStack décrit cette bibliothèque comme étant conçue spécifiquement pour récupérer, mettre en cache, synchroniser et mettre à jour l’état du serveur.
Pensez aux données comme suit :
Users
Projects
Messages
Notifications
Orders
Analytics
Votre interface utilisateur ne possède en réalité aucune de ces informations.
C’est le backend qui les détient.
React Query agit comme couche intermédiaire entre votre UI et ce backend, en assurant la gestion du cycle de vie de ces données.
Au cœur de cette architecture se trouve le Query Cache.
D’après la documentation actuelle de TanStack, QueryCache est la couche de stockage des requêtes — elle contient leurs données, métadonnées et état. Un QueryClient gère ce cache et expose les API que l’application utilise pour y lire, y mettre à jour des éléments, invalider des entrées et interagir avec lui de diverses manières.
C’est précisément pour cette raison que plusieurs parties non liées d’une application peuvent demander la même requête et obtenir des résultats cohérents :
const { data } = useQuery({
queryKey: ['projects'],
queryFn: fetchProjects
})
Cependant, React Query fait bien plus que de simplement mettre en cache une seule réponse.
Il gère le stockage en cache, la déduplication des requêtes, le suivi de la fraîcheur, le rechargement en arrière-plan, la logique de tentative, le nettoyage automatique, les mutations et l’invalidation, tout cela au sein du même système.
Par exemple, après une mise à jour d’un projet :
const queryClient = useQueryClient()
await updateProject(project)
queryClient.invalidateQueries({
queryKey: ['projects']
})
Plutôt que d’indiquer manuellement à dix composants distincts comment mettre à jour leur copie locale du projet, il suffit de dire au système de requêtes :
« Les données serveur derrière cette requête pourraient ne plus être exactes. »
À partir de là, le cache s’occupe de les révalider.
Telle est l’idée fondamentale qui sous-tend TanStack Query.
Il ne cherche pas à devenir un second Redux.
Cela confère à l’état du serveur un cycle de vie propre.
Dès que l’on commence à considérer l’état du serveur comme fondamentalement différent de l’état du client, il devient beaucoup plus facile de comprendre pourquoi une application qui semble, en apparence, avoir besoin d’un store Redux étendu n’en a en réalité pas du tout besoin.
Redux n’a jamais été le problème
Pour être juste, Redux lui-même ne mérite aucune critique ici.
Redux Toolkit reste l’approche officiellement recommandée pour développer avec Redux, et ce dernier reste utile chaque fois qu’une application a réellement besoin d’un état côté client complexe, de transitions prévisibles entre les états, de pipelines de middleware ou d’un modèle d’état unifié.
Les problèmes commencent lorsque les développeurs mettent tout absolument dans un seul store global.
Imaginez une application ayant cette structure :
{
user: {},
projects: [],
teams: [],
notifications: [],
orders: [],
products: [],
analytics: {},
theme: "dark",
sidebarOpen: true
}
D’un premier coup d’œil, tout cela semble appartenir à l’application.
Pourtant, ce n’est pas le cas.
Essayez de poser une question directe :
Qui est vraiment le propriétaire de ces données ?
La liste des projets est-elle quelque chose que l’application React contrôle ?
Pas vraiment.
C’est le backend qui en est le véritable propriétaire.
Un autre utilisateur pourrait-il modifier une commande tant que la fenêtre de votre navigateur reste ouverte ?
Bien sûr que oui.
Une notification pourrait-elle apparaître sans aucune action de votre code React ?
Oui, absolument.
Le serveur pourrait-il révoquer ou modifier unilatéralement les permissions d’un utilisateur ?
Sans aucun doute.
Ainsi, une grande partie de cet « état d’application » n’appartient pas du tout au frontend.
C’est l’état du serveur.
L’état du serveur soulève une catégorie entièrement différente de défis.
Il faut le récupérer.
Il faut le mettre en cache.
Il faut déterminer quand il devient obsolète.
Il faut le récupérer à nouveau.
Il faut le maintenir synchronisé après les modifications.
Il faut gérer les indicateurs de chargement et les états d’erreur.
Il faut tenir compte des tentatives de réessai et des interruptions de connexion réseau.
C’est précisément cet ensemble de problèmes que TanStack Query a été conçu pour résoudre.
Le changement architectural
Une configuration conventionnelle axée sur Redux ressemble généralement à ce flux :
API
↓
Async action / thunk
↓
Reducer
↓
Redux Store
↓
Selector
↓
React Component
Pour de nombreuses applications basées sur des API, ce flux peut être transformé en quelque chose comme ceci :
API
↓
TanStack Query
↓
Query Cache
↓
React Component
La différence peut sembler mineure sur le papier.
C’est faux.
Le véritable changement réside dans le fait que l’on n’a plus besoin de construire manuellement toute la logique nécessaire pour gérer l’état du serveur.
Prenons quelque chose d’aussi courant qu’une liste de projets.
Avec Redux, on commence généralement par :
const initialState = {
data: [],
loading: false,
error: null
}
Puis on ajoute une action asynchrone :
dispatch(fetchProjects())
Suivie par une logique de réducteur qui couvre :
pending
fulfilled
rejected
Et enfin, un sélecteur :
const projects = useSelector(
state => state.projects.data
)
Maintenant, comparons cela avec la version de TanStack Query :
const { data, isPending, error } = useQuery({
queryKey: ['projects'],
queryFn: fetchProjects
})
Il ne s’agit pas simplement d’une réduction du nombre de lignes de code.
La requête elle-même devient l’abstraction qui entoure la ressource du serveur.
Le nom de la clé de requête identifie la ressource suivie.
Le cache conserve le résultat.
La requête surveille son propre état.
Et n’importe quel nombre de composants peut utiliser cette même valeur en mémoire cache.
QueryCache de TanStack Query existe spécifiquement pour conserver les résultats des requêtes ainsi que leur état associé, et QueryClient vous fournit l’interface nécessaire pour travailler avec ce cache.
Le cache de requêtes est essentiellement un stockage global pour les données serveur
Ce pourrait être le concept le plus important ici.
De nombreux développeurs entendent cette expression :
"React Query dispose d’un cache."
Et en déduisent que cela signifie :
"Donc il s’agit simplement de stocker en cache les réponses API."
Mais c’est bien plus que cela.
Le cache de requêtes devient en fait la source unique et partagée pour l’état serveur de votre application.
Imaginez trois composants distincts :
Dashboard
|
+── ProjectList
|
+── ProjectSidebar
|
+── RecentProjects
Tous ont besoin des mêmes données, identifiées par :
['projects']
Il n’est pas nécessaire d’acheminer manuellement ces données serveur vers Redux avant que les trois composants ne lisent dans le store.
Il suffit de demander la même requête là où elle est nécessaire :
useQuery({
queryKey: ['projects'],
queryFn: fetchProjects
})
TanStack Query s’occupe de partager et de mettre en cache ces données en arrière-plan.
L’architecture qui en résulte peut ressembler à ceci :
React App
|
┌─────────┴─────────┐
| |
Client State Server State
| |
Redux / Zustand TanStack Query
| |
UI state Query Cache
D’un coup, tout le système devient beaucoup plus simple à comprendre.
React Query peut-il donc remplacer Redux ?
Dans certaines applications, oui, c’est vraiment possible.
Mais voici la nuance cruciale :
Il ne remplace pas Redux en étant une version supérieure de celui-ci.
Au contraire, il élimine d’abord le besoin de compter sur Redux pour l’état serveur.
C’est une affirmation nettement différente.
La documentation officielle de TanStack Query présente explicitement la gestion de l’état serveur comme un problème distinct de celui de la gestion de l’état client, et souligne que lorsque l’état serveur est géré par React Query, l’état client restant à gérer de manière globale peut considérablement diminuer.
C’est là que les choses deviennent vraiment intéressantes du point de vue architectural.
Vous pourriez aboutir à une structure comme celle-ci :
Client State
theme
sidebar
selectedTab
modal
editor
filters
En parallèle :
Server State
users
projects
orders
notifications
products
analytics
À ce stade, le choix des outils devient bien plus ciblé :
Client State → Redux / Zustand / Context / React
Server State → TanStack Query
Plutôt que d’attendre qu’un seul stockage assume les deux tâches en même temps.
Mais Redux a encore un rôle à jouer
Considérez un type d’application différent, quelque chose de plus proche d’un outil de conception comme Figma.
Vous pourriez finir par stocker des états tels que :
{
selectedLayer,
activeTool,
zoom,
canvasMode,
dragState,
undoStack,
redoStack
}
Rien de tout cela n’est un état serveur.
C’est entièrement sous le contrôle du frontend.
Il change de manière synchrone, en réponse directe aux interactions de l’utilisateur.
Diverses parties de l’interface utilisateur en dépendent simultanément.
Il peut être nécessaire de coordonner des transitions complexes lorsque l’un des états affecte un autre.
C’est précisément dans ce type de scénario qu’un gestionnaire d’état client dédié s’avère utile.
La documentation de TanStack Query souligne un point similaire : un état complexe, piloté par l’interface utilisateur et sans rapport avec le serveur, justifie encore l’utilisation d’un outil spécifiquement conçu pour gérer l’état client.
Ainsi, la conclusion n’est pas « supprimer Redux partout et le remplacer par React Query ». Ce serait une correction excessive.
Et il y a un autre acteur important : RTK Query
Il existe une complication supplémentaire à mentionner.
Redux Toolkit inclut déjà RTK Query, une couche de récupération et de mise en cache des données conçue spécifiquement pour fonctionner au sein d’applications Redux.
Elle peut générer automatiquement des hooks et gérer la récupération des données depuis les endpoints, les états de chargement ainsi que le cache, tout comme TanStack Query.
Ainsi, le véritable changement qui se produit dans cet écosystème n’est pas simplement :
Redux → React Query
Cela ressemble plutôt à cette évolution :
Manual API state in Redux
↓
Dedicated server-state solutions
↓
TanStack Query / RTK Query / Apollo / SWR
Le secteur dans son ensemble prend progressivement conscience du fait que l’état serveur et l’état client sont des responsabilités fondamentalement différentes qui méritent des outils distincts.
Lorsque vous internalisez cette distinction, il devient beaucoup plus facile de comprendre l’architecture globale de l’état.
La règle que j’utilise maintenant
Lorsque vous décidez si une donnée doit faire partie de l’état global, une seule question suffit pour prendre la plupart des décisions :
Qui possède réellement ces données ?
Si la réponse est :
L’arrière-plan
vous avez presque certainement affaire à l’état du serveur.
Si la réponse est :
L’avant-plan
vous avez presque certainement affaire à l’état du client.
Cette seule question vous oriente généralement vers une architecture très différente en fonction du cas.
Par exemple :
Current user ────────── Server
Projects ────────────── Server
Orders ──────────────── Server
Notifications ───────── Server
Theme ───────────────── Client
Modal ───────────────── Client
Selected tab ────────── Client
Editor state ────────── Client
Lorsque vous présentez les choses de cette manière, la structure appropriée devient évidente.
React Query ne tue pas Redux
L’affirmation selon laquelle « React Query remplace Redux » est un peu trompeuse telle qu’elle est formulée.
Ce qui change réellement, c’est quelque chose de plus subtil :
Les développeurs deviennent de mieux en mieux à identifier la catégorie d’état avec laquelle ils ont affaire.
Redux était autrefois le répertoire par défaut pour tout, y compris les réponses serveur.
Server state
↓
TanStack Query
de :
Client state
↓
Redux / Zustand / Context / React
Pour de nombreuses bases de code React modernes, cette simple séparation élimine une part surprenante de la complexité qui était autrefois imputée à Redux lui-même.
L’objectif n’est pas de réduire le nombre de bibliothèques utilisées.
L’objectif est d’arrêter de créer manuellement des infrastructures pour des problèmes qui disposent déjà d’abstractions solides et conçues spécifiquement à cet effet.
Ainsi, la prochaine fois que vous tomberez sur un slice Redux encombré de réponses API, de flags de chargement, de logique d’invalidation du cache et d’actions de rechargement, demandez-vous :
Avez-vous vraiment besoin d’un gestionnaire d’état global pour cela, ou avez-vous simplement réimplémenté React Query manuellement à l’intérieur de Redux ?
Comment gérez-vous cela dans vos applications ?
Conservez-vous actuellement les données serveur dans Redux ou Zustand, faites-vous confiance à TanStack Query, ou adoptez-vous une approche complètement différente ?
Lectures associées
- Dix erreurs cachées des composants React qui ralentissent les applications modernes — Découvrez dix erreurs courantes dans les composants React, allant des lacunes dans l’HTML sémantique à l’absence de mémoisation, ainsi que les solutions nécessaires pour maintenir des applications rapides, accessibles et sans bugs en 2026.
- Résoudre le problème d’overload des props de React avec la composition et les slots — Comprenez pourquoi les props de React à forte charge en configuration génèrent des dettes de maintenance, et comment l’inversion de contrôle, la composition et les slots permettent de créer des composants véritablement réutilisables.