Booster les performances Next.js avec TanStack Query (React Query)
Améliorez les performances Next.js grâce à TanStack Query : cache, revalidation en arrière-plan, mutations et hydration SSR/SSG.

La gestion de l’état serveur est un levier de performance souvent sous-estimé dans une application Next.js. Les schémas manuels (fetch + useEffect) ne passent pas à l’échelle : répétitions, conditions de course, surcoût réseau.
TanStack Query transforme cet enchevêtrement en une couche déclarative de cache : vous définissez la clé, la fonction et la politique de fraîcheur — le reste est automatisé.
Pourquoi le fetching devient un goulot caché ?
Anti‑patterns courants :
- Requêtes identiques dupliquées dans plusieurs composants.
- Transitions de page complètes pour une portion minime de données.
- Confusion entre état UI et état serveur dans un store global.
- Absence de couche de cache → nouvelle requête à chaque navigation.
- Refetch agressif au retour de focus → charge inutile sur l’API.
Résultat : bande passante gaspillée et navigation moins fluide.
TanStack Query normalise fraîcheur, staleness et invalidation → comportement prévisible.
Atouts clés de TanStack Query
- Dé‑duplication et partage du cache.
- Stale‑While‑Revalidate : rendu instantané + mise à jour silencieuse.
- Collecte automatique des queries inactives.
- Invalidation ciblée après mutation.
- Support SSR / SSG + hydration pour SEO et TTFB perçu.
Installation
yarn add @tanstack/react-queryCompatible App Router (Next.js 13/14) sans dépendre des nouveautés 15+.
Fournisseur global QueryClient
1"use client";
2import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
3import { useState, ReactNode } from "react";
4
5export function QueryProviders({ children }: { children: ReactNode }) {
6 const [queryClient] = useState(() => new QueryClient());
7 return <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>;
8}Dans app/layout.tsx :
1import { QueryProviders } from "@/app/query-providers";
2
3export default function RootLayout({ children }: { children: React.ReactNode }) {
4 return (
5 <html lang="fr">
6 <body>
7 <QueryProviders>{children}</QueryProviders>
8 </body>
9 </html>
10 );
11}Fetch impératif vs déclaratif
Sans TanStack Query :
1const [posts, setPosts] = useState([]);
2const [loading, setLoading] = useState(true);
3useEffect(() => {
4 let cancelled = false;
5 fetch("/api/posts")
6 .then(r => r.json())
7 .then(d => { if (!cancelled) { setPosts(d); setLoading(false); } });
8 return () => { cancelled = true; };
9}, []);Avec TanStack Query :
1"use client";
2import { useQuery } from "@tanstack/react-query";
3
4async function fetchPosts() {
5 const res = await fetch("https://jsonplaceholder.typicode.com/posts");
6 if (!res.ok) throw new Error("Échec du chargement");
7 return res.json();
8}
9
10export function PostsList() {
11 const { data, isLoading, isError } = useQuery({
12 queryKey: ["posts"],
13 queryFn: fetchPosts,
14 staleTime: 60_000,
15 });
16 if (isLoading) return <p>Chargement…</p>;
17 if (isError) return <p>Impossible de charger les données.</p>;
18 return <ul>{data.map((p: any) => <li key={p.id}>{p.title}</li>)}</ul>;
19}Avantages : moins de code, réutilisation immédiate, requêtes réduites.
Mutations et invalidation ciblée
1import { useMutation, useQueryClient } from "@tanstack/react-query";
2
3export function AddTodoButton() {
4 const qc = useQueryClient();
5 const mutation = useMutation({
6 mutationFn: async (todo: { title: string }) => {
7 await fetch("/api/todos", {
8 method: "POST",
9 headers: { "Content-Type": "application/json" },
10 body: JSON.stringify(todo),
11 });
12 },
13 onSuccess: () => qc.invalidateQueries({ queryKey: ["todos"] }),
14 });
15 return (
16 <button onClick={() => mutation.mutate({ title: "Apprendre TanStack Query" })}>
17 {mutation.isPending ? "Enregistrement…" : "Ajouter"}
18 </button>
19 );
20}Chaîne claire : action → mutation → invalidation ciblée → UI à jour.
Hydration SSR / SSG (avant 15)
1// pages/posts.tsx
2import { QueryClient, dehydrate } from "@tanstack/react-query";
3import { useQuery } from "@tanstack/react-query";
4
5async function fetchPosts() {
6 const r = await fetch("https://jsonplaceholder.typicode.com/posts");
7 return r.json();
8}
9
10export async function getStaticProps() {
11 const qc = new QueryClient();
12 await qc.prefetchQuery({ queryKey: ["posts"], queryFn: fetchPosts });
13 return { props: { dehydratedState: dehydrate(qc) }, revalidate: 3600 };
14}
15
16export default function PostsPage() {
17 const { data } = useQuery({ queryKey: ["posts"], queryFn: fetchPosts });
18 return (
19 <main>
20 <h1>Tous les articles</h1>
21 <ul>{data?.map((p: any) => <li key={p.id}>{p.title}</li>)}</ul>
22 </main>
23 );
24}Conseils de performance
- Ajuster
staleTimeselon la nature des données. - Désactiver
refetchOnWindowFocussi bruit inutile. - Prefetch sur hover des liens majeurs.
- Invalidation granulaire > globale.
- Centraliser les clés d’interrogation.
- Optimistic UI pour interactions sensibles à la latence.
Pourquoi dans les templates Aniq‑UI ?
- Moins de boilerplate pour l’acheteur.
- Navigation perçue plus rapide.
- Séparation nette état serveur / état UI.
- Impact positif sur Core Web Vitals.
Conclusion
TanStack Query transforme des effets épars en une couche de cache cohérente et scalable. Indispensable pour des bases de code durables et des templates réutilisables.
Voir des exemples concrets ? Parcourez les templates Next.js sur Aniq‑UI.com.
Mots-clés SEO : performance Next.js, React Query Next.js, TanStack Query, templates Next.js, cache Next.js, fetching données Next.js
Cet article vous a été utile?
Vous pourriez aussi aimer

Optimisation des performances Next.js : Guide pratique pour accélérer vos applications

Template gratuit de page d'atterrissage 3D pour sites web de jus, boissons et marketing produit (Next.js + Three.js + GSAP)
