Récupérer des données en React et Next.js, comparé sur une même application
Récupérer des données en React : serveur, TanStack Query, SWR | We.Inc
Choisissez une approche de récupération de données en React grâce à un court quiz, puis comparez les server components, TanStack Query et SWR sur le cache, les mutations et les valeurs par défaut, sur une même application d'exemple.
Récupérez les données côté serveur quand vous le pouvez : dans l'App Router de Next.js, un server component async attend les données avant l'envoi du moindre HTML, sans code de spinner de chargement. Pour des données qui changent pendant que la page est ouverte, utilisez un cache client comme TanStack Query ou SWR, qui gèrent le cache, les nouvelles tentatives et les mutations. Un simple fetch dans useEffect convient aux requêtes ponctuelles.
Quelle approche choisir
Approche
S'exécute où
Cache
Idéal pour
Server component async
Serveur
Pas de cache par défaut ; activez-le avec use cache
Données de page, secrets, requêtes en base de données
TanStack Query
Navigateur
Cache de requêtes indexé par queryKey
Tableaux de bord, mutations, pagination
SWR
Navigateur
Cache indexé par la clé de requête
Vues surtout en lecture qui doivent rester à jour
useEffect + fetch
Navigateur
Aucun, sauf si vous l'écrivez
Une petite requête dans une petite application
Chaque exemple de cette page charge et modifie la même petite liste de notes, donc les différences viennent de l'approche et non de la démo. Répondez aux trois questions ci-dessous pour obtenir une recommandation de départ et l'extrait de code correspondant.
Indiquez si vous utilisez un framework avec des server components, comme l'App Router de Next.js.
Indiquez si les données doivent rester à jour pendant que la page est ouverte, et si les utilisateurs les modifient.
Lisez la recommandation et copiez l'extrait correspondant.
Utilisez les sections de comparaison ci-dessous pour vérifier les valeurs par défaut avant de mettre en production.
Lancez les requêtes ensemble. Deux await à la suite forment une cascade ; créez d'abord les deux promesses puis faites await Promise.all.
Mettez la même queryKey sur chaque useQuery qui lit les mêmes données, pour que les composants partagent une seule requête et une seule entrée de cache.
Après une mutation, invalidez la clé concernée plutôt que de modifier le cache à la main, sauf si vous avez besoin d'une mise à jour optimiste instantanée.
Ne récupérez jamais de secrets dans un client component. Tout ce que le navigateur demande est visible dans l'onglet réseau.
Questions fréquentes
Les requêtes fetch sont-elles mises en cache dans l'App Router de Next.js ?
D'après la documentation actuelle de Next.js, les requêtes fetch ne sont pas mises en cache par défaut et bloquent le rendu jusqu'à leur fin. Les requêtes identiques d'un même rendu sont mémoïsées, et vous activez le cache avec la directive use cache ou diffusez des données fraîches dans Suspense.
Quelles sont les valeurs par défaut importantes de TanStack Query ?
Les données sont périmées immédiatement (staleTime 0), elles sont donc rechargées au montage, au retour sur la fenêtre et à la reconnexion. Les requêtes inutilisées restent en mémoire 5 minutes (gcTime), et les requêtes échouées sont retentées 3 fois avec un backoff exponentiel. Augmentez staleTime si ces rechargements dépassent vos besoins.
TanStack Query ou SWR ?
Les deux mettent en cache par clé et revalident au retour sur la fenêtre et à la reconnexion. TanStack Query intègre davantage d'outils pour les mutations, l'invalidation et les devtools ; SWR a une API plus réduite construite autour de useSWR(key, fetcher). Choisissez-en un par application ; utiliser les deux duplique le cache.
Ai-je encore besoin d'une bibliothèque client avec les server components ?
Souvent pas pour le chargement des pages. Vous en avez besoin quand les données doivent se rafraîchir sans navigation, quand les utilisateurs modifient des données et attendent un retour immédiat, ou pour les listes infinies. Beaucoup d'applications chargent côté serveur et n'utilisent un cache client que sur les écrans interactifs.
Comment vérifier qui est connecté avec Supabase côté serveur ?
Le guide côté serveur de Supabase indique de ne jamais faire confiance à getSession() dans du code serveur. Appelez supabase.auth.getClaims(), qui vérifie la signature du jeton, puis interrogez vos tables ; la sécurité au niveau des lignes (row level security) s'applique toujours à chaque requête.
Le serveur d'abord, puis un cache client là où c'est utile
Un server component peut interroger une base de données ou appeler une API avec des identifiants directement, et le résultat arrive sous forme de HTML. Cela supprime le code d'état de chargement de la plupart des pages et garde les clés hors du bundle du navigateur.
Les écrans interactifs sont différents. Une liste de notes que les gens complètent, filtrent et consultent à nouveau profite d'un cache client qui mémorise les résultats entre les écrans et les rafraîchit en arrière-plan.
Le streaming plutôt que l'attente
Si une requête est lente, enveloppez le composant qui en a besoin dans Suspense avec un fallback. Le reste de la page est envoyé immédiatement et la partie lente arrive en streaming. Un fichier loading.js fait la même chose pour tout un segment de route dans Next.js.
Dans un client component, vous pouvez aussi recevoir une promesse du serveur et la lire avec l'API use de React dans Suspense.
Pourquoi le simple useEffect ne suffit pas
Un fetch dans useEffect n'a pas de cache : chaque montage répète la requête, et il faut gérer à la main les race conditions, le chargement et les erreurs. Cela convient pour un petit widget. Pour tout ce qui est plus gros, une bibliothèque vous apporte tout cela en quelques lignes ; les bases de fetch lui-même sont traitées dans notre guide sur async et fetch.
Les valeurs par défaut qui surprennent
Comportement par défaut
Comportement
fetch serveur Next.js
TanStack Query
SWR
Cache entre les requêtes
Non, activez-le avec use cache
En mémoire, par onglet du navigateur
En mémoire, par onglet du navigateur
Requêtes en double
Mémoïsées dans un même rendu
Partagées par queryKey
Dédupliquées par clé sur 2 secondes
Rechargement au retour sur la fenêtre
Sans objet
Oui, si périmées
Oui
Rechargement à la reconnexion
Sans objet
Oui, si périmées
Oui
Nouvelles tentatives en cas d'échec
À gérer vous-même
3, avec backoff exponentiel
Oui (errorRetryInterval 5000 ms)
Données inutilisées conservées
Sans objet
5 minutes (gcTime)
Pas de valeur par défaut documentée
Éviter les cascades côté serveur
Lancer les deux requêtes, puis les attendre ensemble
Appeler les deux fonctions avant d'attendre signifie qu'aucune n'attend l'autre.
Diffuser une partie lente avec Suspense
Le titre est envoyé tout de suite ; la liste de notes arrive en streaming quand ses données sont prêtes.
Supabase dans un server component
Ceci utilise le helper createClient du guide côté serveur de Supabase pour Next.js (lib/supabase/server.ts, construit sur @supabase/ssr). getClaims() vérifie le jeton de l'utilisateur connecté avant l'exécution de la requête.
Notes de l'utilisateur connecté, chargées côté serveur
La sécurité au niveau des lignes de la table notes décide quelles lignes sont renvoyées.
Choisir une approche
Utilisez-vous des server components (par exemple l'App Router de Next.js) ?
Les données doivent-elles se rafraîchir pendant que la page reste ouverte ?
Les utilisateurs modifient-ils ces données à l'écran ?
Oui
Non
Extrait de départ
Copier l'extrait
Chargez-les dans un server component async. Ajoutez un cache client plus tard, uniquement pour les parties qui deviennent interactives.
Utilisez TanStack Query : useQuery pour lire, useMutation pour écrire, et invalidateQueries pour rafraîchir après un changement.
Utilisez SWR : useSWR garde la vue à jour au retour sur la fenêtre et à la reconnexion avec très peu de code.
Un seul fetch dans useEffect suffit ici. Faites le nettoyage avec un drapeau ignore pour qu'une réponse tardive ne puisse pas écraser un état plus récent.