perf(client): rafraîchir les données sans recharger la page

`staleTime: Infinity` combiné à `refetchOnWindowFocus: false` empêchait toute
revalidation : une donnée chargée à la première visite restait affichée pour
toute la session. Or le serveur agit de son côté — le scheduler publie chaque
minute, les jetons se renouvellent en tâche de fond — sans que le navigateur en
soit averti. D'où la nécessité de recharger la page pour voir quoi que ce soit.

Les compteurs du tableau de bord étaient le cas le plus visible : /api/stats et
/api/posts n'étaient invalidés par aucune mutation de l'application, et ne
pouvaient donc plus bouger du tout.

- Péremption courte (30 s) et rafraîchissement au retour sur l'onglet ou sur
  reconnexion, en remplacement du cache éternel.
- /api/stats et /api/posts, qui dérivent de tout le reste, sont invalidés depuis
  le MutationCache après chaque mutation réussie : aucune mutation ne peut
  raisonnablement se souvenir de le faire, et aucune ne le faisait. Les
  mutations d'authentification en sont exclues, la session étant déjà détruite
  quand la déconnexion aboutit.
- Les trois sondages à 3 s (historique desktop et mobile, reels en cours)
  devenaient inutiles hors traitement en cours. Ils ne s'emballent plus que
  lorsqu'il y a effectivement quelque chose à suivre — une publication dont
  l'heure est passée, une génération en route — et retombent à 30 s sinon. La
  page Historique rechargeait tout l'historique 20 fois par minute.
- La liste des modèles OpenRouter, servie par un appel sortant, garde une
  péremption d'une heure pour ne pas être redemandée à chaque retour d'onglet.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qns6Gcpd95bCHWUxySh4Ew
This commit is contained in:
Claude committed 2026-09-10 06:22:21 +00:00
1 parent d7f002a64f
commit 25bf0981bd
8 files changed
+75 -8

No files matched your search

+33 -4
View File
@@ -1,4 +1,4 @@
import { QueryClient, QueryFunction } from "@tanstack/react-query";
import { MutationCache, QueryClient, QueryFunction } from "@tanstack/react-query";
// Les routes d'authentification elles-mêmes ne doivent jamais déclencher
// de redirection automatique (ex: mauvais mot de passe sur /login).
@@ -88,13 +88,42 @@ export const getQueryFn: <T>(options: {
return await res.json();
};
/**
* Marque les mutations d'authentification, exclues de l'invalidation globale
* ci-dessous. À passer en `mutationKey` : `[AUTH_MUTATION, 'logout']`.
*/
export const AUTH_MUTATION = "auth";
export const queryClient = new QueryClient({
// Les compteurs du tableau de bord et la liste des posts dérivent de tout le
// reste : publier, supprimer un média, générer un texte… Aucune mutation ne
// peut raisonnablement se souvenir de les invalider, et aucune ne le faisait :
// ils restaient figés jusqu'au rechargement de la page. On les invalide donc
// ici, une bonne fois, après chaque mutation réussie.
mutationCache: new MutationCache({
onSuccess: (_data, _variables, _context, mutation) => {
// Sauf pour l'authentification : au moment où la déconnexion réussit, la
// session est déjà détruite. Relancer des requêtes ici ne produirait que
// des 401 et une redirection brutale, avant même que le cache soit vidé.
if (mutation.options.mutationKey?.[0] === AUTH_MUTATION) return;
queryClient.invalidateQueries({ queryKey: ["/api/stats"] });
queryClient.invalidateQueries({ queryKey: ["/api/posts"] });
},
}),
defaultOptions: {
queries: {
queryFn: getQueryFn({ on401: "throw" }),
refetchInterval: false,
refetchOnWindowFocus: false,
staleTime: Infinity,
// Le serveur agit de son côté — le scheduler publie toutes les minutes, le
// renouvellement des jetons tourne en tâche de fond — sans que le
// navigateur en soit averti. Avec `staleTime: Infinity`, un écran restait
// sur le cache de sa première visite pour toute la session : d'où la
// nécessité de recharger la page pour voir quoi que ce soit. Une
// péremption courte, plus un rafraîchissement au retour sur l'onglet,
// suffit à garder l'affichage juste sans marteler l'API.
staleTime: 30_000,
refetchOnWindowFocus: true,
refetchOnReconnect: true,
retry: false,
},
mutations: {