6 min lecture19 août 2024resources

React query : Comment organiser son code

Comment organiser ses fichiers avec React Query

Que vous ayez à interagir avec une API REST, GraphQL ou d'autres sources de données asynchrones, React Query offre une solution robuste et efficace pour gérer le fetching, la mise à jour, la mise en cache et la synchronisation des données.

Depuis que je l’ai essayé la première fois, je l’intègre dans quasiment tous les projets front.

Pourquoi utiliser React Query ?

  1. Simplification de la Gestion des États Complexes:
    • Gestion automatique des états loading, error, success.
    • Réduction significative du code nécessaire pour gérer les états asynchrones.
  2. Mise en Cache et Synchronisation:
    • Mécanisme de mise en cache intelligent qui minimise les appels réseau redondants.
    • Révalidation automatique des données vieillissantes
  3. Optimisation des Performances:
    • Optimisation des performances grâce à la stratégie de préfetching.
    • Invalidations et refetches automatiques basés sur la mutabilité des données et les hooks de lifecycle de React.
  4. API Intuitive et Flexible:some text
    • Une API qui suit les meilleures pratiques du développement React.
    • Support complet des requêtes dynamiques et pagination.
=> Allez lire la doc pour plus de détails : https://tanstack.com/query/v3

Installation et Configuration de Base

Pour commencer avec React Query, vous pouvez l'installer via npm ou yarn:


# ou


Ensuite, vous devez importer et configurer le QueryClient et le QueryClientProvider dans votre application:


Fetching de Données

L'une des tâches les plus courantes consiste à récupérer des données depuis une API. React Query vous permet de le faire simplement avec le hook useQuery:


Mutation de Données

Pour les opérations de mutation (ajout, mise à jour, suppression), React Query fournit le hook useMutation:


Architecture adaptée pour scaler

Très vite, si vous utilisez ces bouts de code dans toute votre app, vous allez vous retourner avec des composant difficiles à lire. Je vous partage donc comment j’organise mon code pour utiliser cette lib de manière propre et scalable.

I - Création d’un dossier /api

Il est toujours bon de gérer les appels vers l’extérieur depuis votre app à un seul endroit. Je créer donc un dossier /api à la racine de mon projet.

Si vous utilisez NextJS, /api est un nom réservé. Utilisez un autre nom

1 - /dummyjson

Dans le dossier /api, je créer systématiquement un sous dossier par API externe. Dans notre cas /dummyjson

Dans ce sous-dossier, je créer un fichier queries.ts

C'est dans ce fichier que nous allons définir toutes les routes exposées par notre API. 

/api/dummyjson/queries.ts


Vous pouvez également créer un fichier models.ts dans lequel vous mettrez tous les types issues de l'API. 

Il existe plusieurs outils pour générer les types du backend (openapi-generator par exemple)

/api/dummyjson/models.ts


2 - QueryClient.ts

Maintenant que nous pouvons communiquer avec notre API, nous pouvons désormais configurer notre client React Query.

Commençons par créer un fichier que nous appellerons queryClient.ts

Ce fichier queryClient.ts va nous servir à configurer notre client React Query et gérer les erreurs des requêtes et des mutations ainsi que certaines options de comportement par défaut des requêtes.

/api/queryClient.ts


Voici une explication détaillée de chaque section du fichier :

1. Imports


  • @tanstack/react-query: Importation des classes principales pour gérer les requêtes et les mutations.
  • getQueryKey: Une fonction utilitaire qui retourne le nom des requêtes de manière typée

2. _handleError Function


Cette fonction privée _handleError gère les erreurs des requêtes et des mutations. Selon le code d'erreur et le type (mutation ou query), elle affiche un message via un événement personnalisé snackbar.

  • Erreur 502, 503, 504: Indiquent que le service est indisponible.
  • Autres erreurs: Affiche un message d'erreur générique généré grâce à i18next

3. handleQueryError et handleMutationError


5. Configuration du query client


Ce bloc configure le QueryClient avec les comportements suivants :

  • Caches des erreurs: Gère les erreurs avec handleMutationError et handleQueryError.
  • Options par défaut pour les requêtes:
    • gcTime: Définit le temps de collecte du caches à 30 jours.
    • retry: Définit la politique de retry (réessayer) des requêtes échouées.some text
      • Ne réessaie pas pour certaines erreurs spécifiques (404, 401, 403, 418).
      • Réessaie au maximum 2 fois pour d'autres erreurs.
    • refetchOnMount, refetchOnWindowFocus, refetchOnReconnect: Désactivés pour éviter les refetchs automatiques.

Conclusion

Ce fichier configure les comportements des requêtes et des mutations définies avec React Query pour gérer les erreurs de manière centralisée et afficher les messages d'erreur via un système de snackbar. Il définit également des options par défaut pour les requêtes, comme la politique de retry et le temps de collecte du cache.

De cette façon, vous gérez vos erreurs en un seul endroit. Nous verrons plus bas comment afficher une snackbar.

3 - Provider

Dans un dossier /providers, créez un fichier QueryClientProvider.tsx

/providers/QueryClientProvider.tsx


Il faudra importer ce provider au niveau du fichier de base de votre app. 

4 - Les hooks

Il ne nous reste plus qu'a définir les hooks React Query pour ensuite utiliser nos données. 

Je vous conseil de créer un fichier de hooks par objet. 

Ici nous gérons les todos. Mais nous pourrions créer aussi un fichier pour les posts, les users ... etc.

/api/dummyjson/todos.ts


Ce fichier nous permet de gérer facilement la donnée des todos. Notez les callbacks utilisés dans les mutations. Cela nous permet d'invalider le cache nécessaire lorsque l'on sait qu'une mutation va l'impacter. Ici, lorsque nous mettons à jour à jour une todo, nous savons que la liste des todos et le détail de la todo en question aurons leur cache obsolète. queryClient.invalidateQueries va forcer React Query à refetch la donnée concernée lorsqu'elle sera demandée.

5 - Utilisation dans les composants

Voilà, il ne reste plus qu'à manipuler la donnée dans les composants grâce aux hooks que nous venons de créer. 


6 - La snackbar

Vous vous souvenez de la création du CustomEvent dans la gestion d'erreur ? 

/api/queryClient.ts


Ce bout de code nous permet d'écouter de n'importe où la présence d'une erreur venant de l'API.

Voici ci-dessous un exemple d'utilisation de cet évènement.

Créez un fichier /providers/SnackbarProvider.tsx et importez le ensuite dans le fichier principale de votre projet. 


Conclusion

L'architecture que vous propose vous permettra d'itérer sur des projets complexes faisant appel à plusieurs API sans perdre en lisibilité dans vos composants. Elle est le fruit de 5 ans d'expérience sur cette librairie dont j'ai beaucoup de mal à me passer.