Qu’est-ce que React Query et comment l’utiliser ? Pour les systèmes de production
Guide pratique sur ce qu’est React Query et comment l’utiliser dans les systèmes de production : contrats, vérifications et emplacements prévus pour intégrer du code destiné aux équipes qui adoptent ce pattern.
Les notes suivantes reconstituent un parcours pratique à partir de « Started with React Query ». L’accent est mis sur les contrats, les vérifications et les placeholders de code à insérer, plutôt que sur une approche motivante. Lors de la phase d’aperçu, notez d’abord le contrat : les entrées requises, le signal de succès et ce qui se passe en cas d’échec partiel. Cette liste de contrôle permet de rester honnête lors des modifications ultérieures du code. Considérez cette phase comme un contrat entre les entrées et les sorties validées. Donnez des noms aux éléments générés, définez des vérifications de succès et refusez les terminations partielles silencieuses.
État serveur vs état client
La relation entre l’état du serveur et l’étape du client fonctionne le mieux lorsqu’elle est considérée comme une donnée mesurable. Capturez un exemple parfait, un cas d’échec ainsi que la note de réversion avant d’élargir le périmètre. Enregistrez les temps d’exécution ainsi que le coût des tokens ou des requêtes à côté des résultats fonctionnels. Une visibilité précoce des coûts permet d’éviter des factures inattendues lorsque le processus passe de la démonstration aux environnements partagés. Gardez les opérations de rendu peu coûteuses et reportez les calculs onéreux à l’après-mémorisation, uniquement après avoir effectué des mesures. Une mémorisation prématurée peut cacher des bugs liés à des données obsolètes.
Traditionnellement, c’est ainsi que nous récupérons les données
Traditionnellement, c’est ainsi que l’architecture fonctionne le mieux lorsqu’elle est considérée comme une surface mesurable. Capturez un exemple réussi, un cas d’échec et la note de réversion avant d’élargir le périmètre. Conservez la configuration en dehors du code de l’application. Les fichiers d’environnement, les bases de données secrètes et les indicateurs fonctionnels doivent être regroupés en un seul endroit que les opérateurs peuvent auditer sans devoir lire l’ensemble du système. Maintenez le coût des opérations de rendu faible et reportez les calculs coûteux à la mise en mémoire uniquement après avoir effectué des mesures. Une mise en mémoire prématurée peut cacher des erreurs liées à des données obsolètes.
const [users, setUsers] = useState([])
const [loading, setLoading] = useState(false)
const [error, setError] = useState(null)
useEffect(() => {
async function fetchUsers() {
try {
setLoading(true) const res = await fetch(
"https://jsonplaceholder.typicode.com/users"
) const data = await res.json() setUsers(data)
} catch (err) {
setError(err)
} finally {
setLoading(false)
}
} fetchUsers()
Avec React Query, le code ci-dessus devient :
Avec React Query, cette étape fonctionne le mieux lorsqu’elle est considérée comme une surface mesurable. Capturez un exemple idéal, un cas d’échec et des notes de réversion avant d’élargir le périmètre. Documentez à la fois le parcours réussi et celui de récupération. Les tentatives de réessai, les contrôles humains et le traitement des messages non livrés font partie intégrante du produit, et non d’une mise en forme ultérieure. Maintenez les opérations de rendu peu coûteuses et reportez les calculs coûteux à l’après-mémorisation, uniquement après avoir effectué des mesures. Une mémorisation prématurée peut cacher des bugs liés à des props obsolètes.
function Users() {
const {
data,
isLoading,
error
} = useQuery({
queryKey: ["users"],
queryFn: fetchUsers
})
if (isLoading) {
return <p>Loading...</p>
} if (error) {
return <p>Something went wrong</p>
} return (
<ul>
{data.map(user => (
<li key={user.id}>
{user.name}
</li>
))}
</ul>
)
}
Avec React Query, cette étape fonctionne le mieux lorsqu’elle est considérée comme une surface mesurable. Capturez un exemple idéal, un cas d’échec et des notes de réversion avant d’élargir le périmètre. Considérez cette étape comme un contrat entre les entrées et les sorties validées. Donnez des noms aux artefacts, définez des critères de succès et refusez toute complétion partielle silencieuse.
Alors, comment l’utilisons-nous concrètement ?
Pour cela, comment devons-nous organiser les éléments nécessaires, définir les entrées, l’ responsable de l’étape et les critères d’arrêt avant de modifier le code ? Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu, sans avoir à deviner l’état caché. Enregistrez les temps d’exécution ainsi que le coût des jetons ou des requêtes à côté des résultats fonctionnels. Une visibilité précoce des coûts permet d’éviter des factures inattendues lorsque le processus passe de l’environnement de démonstration à des environnements partagés. Placez l’état en même endroit que le composant responsable de la mutation ; placer tout dans un stockage global rend plus difficile l’identification des erreurs liées aux temps d’exécution.
1. Préparation
Pendant l’étape de configuration initiale, définissez les entrées, le responsable de l’étape et les critères d’arrêt avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Conservez la configuration en dehors du code de l’application. Les fichiers d’environnement, les bases de données secrètes et les indicateurs fonctionnels doivent être regroupés en un seul endroit que les opérateurs peuvent auditer sans avoir à lire l’ensemble du système. Placez l’état au même endroit que le composant responsable de la mutation. Mettre tout dans un stockage global rend plus difficiles à détecter les erreurs de synchronisation temporelle.
npm install @tanstack/react-query
const queryClient = new QueryClient();
root.render(
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
);
2. Récupération de données avec useQuery
Pour la phase 2 « Récupération de données avec étape », définissez les entrées, le responsable de l’étape et les critères de sortie avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Documentez conjointement le parcours normal et le parcours de récupération. Les tentatives répétées, les contrôles humains et la gestion des messages non livrés font partie intégrante du produit, et non d’une mise en forme ultérieure. Placez l’état au même endroit que le composant responsable de la mutation. Mettre tout en un stockage global rend les erreurs liées aux délais plus difficiles à détecter. Pour la phase 2 « Récupération de données avec étape », définissez les entrées, le responsable de l’étape et les critères de sortie avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Considérez cette étape comme un contrat entre les entrées et les sorties validées. Nommez les artefacts, définissez des vérifications de succès et refusez toute complétion partielle silencieuse.
const { data,
isPending,
error } = useQuery({
queryKey: ["users"],
queryFn: fetchUsers
})
2.1. Fonction de requête
Lors de l’étape 2.1 « Fonction de requête », notez d’abord les exigences : entrées nécessaires, signal de succès et conséquences en cas d’échec partiel. Cette liste de contrôle permet de rester honnête lors des modifications ultérieures du code. Enregistrez les temps d’exécution ainsi que le coût en tokens ou en requêtes à côté des résultats fonctionnels. Une visibilité précoce des coûts évite les factures inattendues lorsque le processus passe de l’environnement de démonstration à des environnements partagés. Considérez les effets comme une synchronisation avec le monde extérieur, et non comme un substitut aux valeurs dérivées lors du rendu.
async function fetchUsers() {
const res = await fetch("/api/users")
if (!res.ok) {
throw new Error("Failed to fetch users")
}
return res.json()
}
useQuery({
queryKey: ["users"],
queryFn: fetchUsers
})
2.2. Clé de requête
Lorsque vous travaillez sur l’étape clé 2 2 Query, notez d’abord les exigences : les entrées requises, le signal de succès, ainsi que ce qui se passe en cas d’échec partiel. Cette liste de contrôle permet de rester honnête lors des modifications ultérieures du code. Conservez la configuration en dehors du code de l’application. Les fichiers d’environnement, les bases de données secrètes et les indicateurs fonctionnels doivent être regroupés en un seul endroit que les administrateurs peuvent auditer sans devoir lire l’ensemble du système. Considérez les effets comme une synchronisation avec le monde extérieur, et non comme un substitut aux valeurs dérivées lors du rendu.
3. Mémorisation en cache
Lors de la mise en œuvre des 3 étapes de mise en cache, notez d’abord le contrat : les entrées requises, le signal de succès et ce qui se passe en cas d’échec partiel. Cette liste de contrôle permet de garantir l’intégrité des modifications ultérieures du code. Documentez ensemble le parcours normal et le parcours de récupération. Les tentatives répétées, les contrôles humains et la gestion des messages non livrés font partie intégrante du produit, et non d’améliorations ultérieures. Considérez les effets comme une synchronisation avec le monde extérieur, et non comme un substitut aux valeurs dérivées lors du rendu. Lors de la mise en œuvre des 3 étapes de mise en cache, notez d’abord le contrat : les entrées requises, le signal de succès et ce qui se passe en cas d’échec partiel. Cette liste de contrôle permet de garantir l’intégrité des modifications ultérieures du code. Considérez cette étape comme un contrat entre les entrées et les sorties validées. Donnez des noms aux artefacts, définites des vérifications de succès et refusez les terminations partielles silencieuses.
4. staleTime
La phase 4 de staleTime fonctionne le mieux lorsqu’elle est considérée comme une surface mesurable. Capturez un transcript idéal, un cas d’échec et la note de rollback avant d’élargir le périmètre. Enregistrez les temps d’exécution ainsi que le coût des tokens ou des requêtes à côté des résultats fonctionnels. Une visibilité précoce des coûts permet d’éviter des factures inattendues lorsque le parcours passe de l’environnement de démonstration à des environnements partagés. Gardez les opérations de rendu peu coûteuses et reportez les calculs onéreux à l’après-mémorisation, uniquement après avoir effectué des mesures. Une mémorisation prématurée peut cacher des bugs liés aux propriétés obsolètes.
useQuery({
queryKey: ["users"],
queryFn: fetchUsers,
staleTime: 60,000 // 60 seconds
})
Pourquoi avons-nous besoin de staletime ??
La démarche « Pourquoi avons-nous besoin de ce stade ? » fonctionne le mieux lorsqu’elle est traitée comme une surface mesurable. Capturez un transcript exemplaire, un cas d’échec et la note de réversion avant d’élargir le périmètre. Gardez la configuration en dehors du code de l’application. Les fichiers d’environnement, les bases de données secrètes et les indicateurs fonctionnels doivent être regroupés en un seul endroit que les opérateurs peuvent auditer sans devoir lire l’ensemble du système. Maintenez le traitement de rendu peu coûteux et reportez les calculs coûteux à la mise en mémoire uniquement après avoir effectué des mesures. Une mise en mémoire prématurée peut cacher des bugs liés à des propriétés obsolètes.
Comprendre staleTime
La phase Understanding staleTime fonctionne le mieux lorsqu’elle est considérée comme une surface mesurable. Capturez un enregistrement idéal, un cas d’échec et la note de rollback avant d’élargir le périmètre. Documentez ensemble le parcours normal et le parcours de récupération. Les tentatives répétées, les contrôles humains et le traitement des messages non livrés font partie intégrante du produit, et non d’une mise en forme ultérieure. Maintenez les opérations de rendu peu coûteuses et reportez les calculs onéreux à la mise en mémoire uniquement après avoir effectué des mesures. Une mise en mémoire prématurée peut cacher des bugs liés aux propriétés obsolètes. La phase Understanding staleTime fonctionne le mieux lorsqu’elle est considérée comme une surface mesurable. Capturez un enregistrement idéal, un cas d’échec et la note de rollback avant d’élargir le périmètre. Considérez cette phase comme un contrat entre les entrées et les sorties validées. Donnez des noms aux artefacts, définez des vérifications de succès et refusez toute complétion partielle silencieuse.
User visits page
↓
Fetch users
↓
User navigates away
↓
User comes back
↓
Fetch users again
staleTime: 5 * 60 * 1000
5. gcTime
Pour l’étape 5 gcTime, définissez les entrées, le responsable de l’étape et les critères de fin avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Enregistrez les temps d’exécution ainsi que le coût des jetons ou des requêtes à côté des résultats fonctionnels. Une visibilité précoce des coûts évite les factures inattendues lorsque le parcours passe de l’environnement de démonstration à des environnements partagés. Placez l’état au même endroit que le composant responsable de la mutation. Mettre tout dans un stockage global rend les erreurs liées aux temps d’exécution plus difficiles à détecter.
useQuery({
queryKey: ["users"],
queryFn: fetchUsers,
gcTime: 60000
})
Quelle est la différence entre staleTime et gcTime ?
Pendant l’étape « Quelle est la différence ? », définissez les entrées, le responsable de l’étape et les critères de fin avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Conservez la configuration en dehors du code de l’application. Les fichiers d’environnement, les bases de données secrètes et les indicateurs fonctionnels doivent être regroupés en un seul endroit que les opérateurs peuvent auditer sans avoir à lire l’ensemble du système. Placez l’état au même endroit que le composant responsable de la mutation. Mettre tout dans un stockage global rend les erreurs liées aux délais plus difficiles à détecter.
6. Récupération des données
Pour l’étape 6 de rechargement, définissez les entrées, le responsable de l’étape et les critères d’arrêt avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Documentez ensemble le parcours normal et le parcours de récupération. Les tentatives répétées, les contrôles humains et la gestion des messages non livrés font partie intégrante du produit, et non d’une mise en forme ultérieure. Placez l’état au même endroit que le composant responsable de la mutation. Mettre tout en un stock global rend les erreurs liées aux délais plus difficiles à détecter. Pour l’étape 6 de rechargement, définissez les entrées, le responsable de l’étape et les critères d’arrêt avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Considérez cette étape comme un contrat entre les entrées et les sorties validées. Donnez des noms aux artefacts, définissez des vérifications de succès et refusez les terminations partielles silencieuses.
const { refetch } = useQuery(...)
refetch()
useQuery({
queryKey: ["users"],
queryFn: fetchUsers,
refetchInterval: 30,000
})
7. Mutations — Création, mise à jour, suppression
Lorsque vous travaillez sur l’étape des 7 mutations de création et de mise à jour, notez d’abord les exigences du contrat : entrées requises, signal de succès et conséquences en cas d’échec partiel. Cette liste de contrôle permet de rester honnête lors des modifications ultérieures du code. Enregistrez les temps d’exécution ainsi que le coût des tokens ou des requêtes à côté des résultats fonctionnels. Une visibilité précoce des coûts évite les factures inattendues lorsque le projet passe de l’environnement de démonstration à des environnements partagés. Considérez les effets comme une synchronisation avec le monde extérieur, et non comme un substitut aux valeurs dérivées lors du rendu.
async function createUser(user) {
const response = await fetch(
"https://jsonplaceholder.typicode.com/users",
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(user),
}
);
if (!response.ok) {
throw new Error("Failed to create user");
}
return response.json();
}
import { useMutation } from "@tanstack/react-query";
function CreateUser() {
const mutation = useMutation({
mutationFn: createUser,
});
return (
<button
onClick={() =>
mutation.mutate({
name: "John Doe",
email: "john@example.com",
})
}
disabled={mutation.isPending}
>
{mutation.isPending ? "Creating..." : "Create User"}
</button>
);
}
export default CreateUser;
Button click
↓
mutation.mutate(user)
↓
createUser(user)
↓
POST request
↓
Server
7.1. États des mutations
Lorsque vous travaillez sur l’étape des 7 états de mutation, notez d’abord les exigences : entrées requises, signal de succès, et ce qui se passe en cas d’échec partiel. Cette liste de contrôle permet de rester honnête lors des modifications ultérieures du code. Conservez la configuration en dehors du code de l’application. Les fichiers d’environnement, les bases de données secrètes et les indicateurs fonctionnels doivent être regroupés en un seul endroit que les administrateurs peuvent auditer sans devoir lire l’ensemble du système. Considérez les effets comme une synchronisation avec le monde extérieur, et non comme un substitut aux valeurs dérivées lors du rendu.
const {
mutate,
isPending,
isSuccess,
isError,
error,
data,
} = useMutation({
mutationFn: createUser,
});
<button
onClick={() => mutate({ userName: "delfina ghimire" })}
disabled={isPending}
>
{isPending ? "Creating..." : "Create user"}
</button>
8. Client de requêtes
Lors de la réalisation des 8 étapes du Query Client, notez d’abord le contrat : les entrées requises, le signal de succès et ce qui se passe en cas d’échec partiel. Cette liste de contrôle permet de rester honnête lors des modifications ultérieures du code. Documentez ensemble le parcours normal et le parcours de récupération. Les tentatives répétées, les contrôles humains et la gestion des messages non livrés font partie intégrante du produit, et non d’améliorations ultérieures. Considérez les effets comme une synchronisation avec le monde extérieur, et non comme un substitut aux valeurs dérivées lors du rendu. Lors de la réalisation des 8 étapes du Query Client, notez d’abord le contrat : les entrées requises, le signal de succès et ce qui se passe en cas d’échec partiel. Cette liste de contrôle permet de rester honnête lors des modifications ultérieures du code. Considérez cette étape comme un contrat entre les entrées et les sorties validées. Donnez des noms aux artefacts, définez des contrôles de succès et refusez les terminations partielles silencieuses.
9. Invalidation de la requête
La phase de invalidation des 9 requêtes fonctionne le mieux lorsqu’elle est considérée comme une surface mesurable. Capturez un enregistrement exemplaire, un cas d’échec et la note de réversion avant d’élargir le périmètre. Enregistrez les temps d’exécution ainsi que le coût des tokens ou des requêtes à côté des résultats fonctionnels. Une visibilité précoce des coûts évite des factures inattendues lorsque le processus passe de l’environnement de démonstration à des environnements partagés. Gardez les opérations de rendu peu coûteuses et reportez les calculs onéreux à la mise en mémoire après avoir effectué des mesures ; une mise en mémoire prématurée peut cacher des bugs liés à des données obsolètes.
[
{ id: 1, userName: "delfina ghimire" },
{ id: 2, userName: "spiderman ghimire" },
]
mutation.mutate({
userName: "ironman ghimire",
});
const queryClient = useQueryClient();
const mutation = useMutation({
mutationFn: createUser,
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["users"],
});
},
});
Create Users (Mutation)
↓
Server data changes
↓
Invalidate ["users"]
↓
Query becomes stale
↓
Refetch
↓
UI gets fresh data
Invalidation vs. Récupération
La phase « Invalidate vs Refetch » fonctionne le mieux lorsqu’elle est considérée comme une surface mesurable. Capturez un exemple idéal, un cas d’échec et la note de rollback avant d’élargir le périmètre. Gardez la configuration en dehors du code de l’application. Les fichiers d’environnement, les stocks de secrets et les flags fonctionnels doivent être regroupés en un seul endroit que les opérateurs peuvent auditer sans devoir lire l’ensemble du système. Maintenez le coût des opérations de rendu faible et reportez les calculs coûteux à la mise en mémoire uniquement après avoir effectué des mesures. Une mise en mémoire prématurée peut cacher des bugs liés à des propriétés obsolètes.
Conclusion
La phase de Conclusion fonctionne le mieux lorsqu’elle est considérée comme une surface mesurable. Capturez un enregistrement idéal, un cas d’échec et la note de réversion avant d’élargir le périmètre. Documentez ensemble le parcours réussi et le parcours de récupération. Les tentatives répétées, les contrôles humains et le traitement des messages non livrés font partie intégrante du produit, et non d’une mise en forme ultérieure. Maintenez les coûts de rendu faibles et reportez les calculs coûteux à la mise en mémoire uniquement après avoir effectué des mesures. Une mise en mémoire prématurée peut cacher des bugs liés à des données obsolètes. La phase de Conclusion fonctionne le mieux lorsqu’elle est considérée comme une surface mesurable. Capturez un enregistrement idéal, un cas d’échec et la note de réversion avant d’élargir le périmètre. Considérez cette phase comme un contrat entre les entrées et les sorties validées. Nommez les artefacts, définites des critères de succès et refusez toute complétion partielle silencieuse.
En résumé
Pour l’étape TL DR, définissez les entrées, le responsable de l’étape et les critères d’arrêt avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché. Enregistrez les temps d’exécution ainsi que le coût des tokens ou des requêtes à côté des résultats fonctionnels. Une visibilité précoce des coûts évite les factures inattendues lorsque le processus passe d’un environnement de démonstration à des environnements partagés. Placez l’état au même endroit que le composant responsable de la mutation ; placer tout dans un stockage global rend les erreurs liées aux temps d’exécution plus difficiles à détecter.
Liste de contrôle opérationnelle
Pour l’étape de la liste de contrôle opérationnelle, définissez les entrées, le responsable de l’étape et les critères d’arrêt avant de modifier le code. Les opérateurs doivent pouvoir relancer l’étape à partir d’un point de contrôle connu sans deviner l’état caché.
Préférez des unités petites et testables plutôt que des scripts complexes. Lorsqu’une étape échoue, l’erreur doit indiquer une seule responsabilité et non un processus embrouillé.
Placez l’état au même endroit que le composant qui gère la mutation. Mettre tout dans un stockage global rend les bugs liés aux délais plus difficiles à détecter.
Rédigez un guide de procédures succinct : comment rotationner les clés, comment vider la file d’attente, comment annuler la dernière ingestion.
Considérez cette étape comme un contrat entre les entrées et les sorties validées. Nommez les artefacts, définez des vérifications de succès, et refusez toute mise à jour partielle silencieuse.
Placez l’état au même endroit que le composant qui gère la mutation. Mettre tout dans un stockage global rend les bugs liés aux délais plus difficiles à détecter.
Au préalable de promouvoir l’ensemble technique, figez les versions, conservez une transcription exemplaire pour le chemin critique, et vérifiez les étapes de réversion. Les environnements partagés nécessitent des limites de fréquence, des contrôles d’attribution, ainsi qu’un responsable clair pour la rotation des secrets. Préférez une fiabilité solide à des démonstrations brillantes mais ponctuelles.
Note pour le lot 1aa45226c385 : gardez les clés du fournisseur hors du répertoire, fixez un plafond pour les tokens par session, et stockez les transcriptions à côté des fichiers de test afin que les remplacements ultérieurs de modèles restent comparables.