Accueil / Articles / Comment React Query a réduit de 500 lignes la couche API d’une application React Native

Comment React Query a réduit de 500 lignes la couche API d’une application React Native

Une étude de cas réelle sur React Native montrant comment le passage d’un chargement de données manuel via useEffect à React Query a permis d’éliminer le code redondant et d’améliorer le cache ainsi que la gestion hors ligne.

1364 mots

Introduction

Il y a quelque temps, une base de code React Native que vous pourriez reconnaître a rencontré un problème familier.

Presque chaque écran nécessitant des données à distance suivait le même schéma :

  • Des appels de récupération de données insérés à l’intérieur de useEffect
  • Plusieurs indicateurs de chargement distincts
  • Des blocs personnalisés pour gérer les erreurs
  • Une logique de mise à jour par tiraillement développée manuellement
  • Des mécanismes de tentative automatique
  • Des solutions temporaires pour le stockage en mémoire locale

D’un point de vue fonctionnel, rien de tout cela n’était défectueux. Mais maintenir cette cohérence sur des dizaines d’écrans est devenu une véritable charge en termes de maintenance.

Le passage à React Query (de TanStack) a permis à l’équipe d’éliminer une grande quantité de code réseau répétitif, tout en obtenant un meilleur mécanisme de mise en cache, une gestion plus propre du chargement et un fonctionnement hors ligne plus fiable. Cette bibliothèque intègre un mécanisme de mise en cache des requêtes, un rechargement automatique en arrière-plan et une logique sensible au réseau, ce qui réduit fortement le besoin d’écrire soi-même cette mécanique de gestion d’état.

Ce qui suit présente une comparaison côte à côte de l’ancienne approche manuelle par rapport à la version React Query, en s’appuyant sur des exemples tirés de vraies interfaces React Native en production.

Les problèmes liés à la gestion traditionnelle des API

La configuration d’une interface typique ressemblait à peu près à ceci :

const [data, setData] = useState([]);
const [loading, setLoading] = useState(false);
const [refreshing, setRefreshing] = useState(false);
const [error, setError] = useState(null);

useEffect(() => {
  fetchData();
}, []);
const fetchData = async () => {
  try {
    setLoading(true);
    const response = await api.getPosts();
    setData(response);
  } catch (err) {
    setError(err);
  } finally {
    setLoading(false);
  }
};

Cette même structure de base réapparaissait sans cesse dans toute l’application.

Chaque interface devait gérer de manière indépendante :

  • Un indicateur de chargement
  • Un indicateur d’erreur
  • Gestion des tentatives de réessai
  • Logique de mise à jour par tirage
  • Sa propre méthode de mise en cache
  • Déclencheurs manuels de récupération des données
  • Au fur et à mesure que l’application grandissait, il devenait de plus en plus difficile de maintenir la cohérence de ce schéma répétitif.

    Apparition de React Query

    Au même écran, réécrit avec React Query, on aboutit à ceci :

    const { data, isLoading, error, refetch } = useQuery({
      queryKey: ["posts"],
      queryFn: fetchPosts,
    });
    

    C’est toute l’implémentation.

    React Query gère automatiquement tout ce qui suit :

    • Indicateurs de chargement
    • États d’erreur
    • Déduplication des requêtes en cours identiques
    • Récupération des données en arrière-plan
    • Gestion de la cache
    • Réessai des requêtes échouées
    • Réaction à la réconnexion au réseau

    La plupart de ces fonctionnalités sont disponibles gratuitement dès le départ, et il est possible de les ajuster via des options telles que staleTime, gcTime, la configuration des tentatives de réessai et les paramètres de récupération des données.

    Comparaison n°1 : Demandes réseau

    Au préalable de React Query

    Imaginez trois écrans distincts qui ont tous besoin des mêmes données de profil utilisateur.

    Sans aucun niveau de mise en cache partagée, chacun envoie sa propre demande :

    Profile Screen → API Call
    Settings Screen → API Call
    Dashboard Screen → API Call
    

    Résultat : trois appels réseau séparés pour les mêmes données.

    Avec React Query

    Profile Screen → API Call
    Settings Screen → Cached Data
    Dashboard Screen → Cached Data
    

    Résultat cette fois : un seul appel réseau.

    React Query stocke les résultats sous une clé de requête et partage ces données mises en cache avec tous les composants qui les demandent. Tout écran qui demande ensuite la même clé obtient immédiatement la valeur en cache, tandis qu’un rechargement en arrière-plan peut la mettre à jour silencieusement.

    Résultat en production

    Sur les écrans que les utilisateurs consultent fréquemment, cela se traduit par :

    • Bien moins de demandes dupliquées vers l’API
    • Moins de charge sur les serveurs backend
    • Transitions plus rapides entre écrans

    Comparaison n°2 : Efficacité du cache

    On peut dire que c’est là que React Query apporte la plus grande valeur ajoutée.

    Lorsque la même requête est de nouveau sollicitée avant que sa copie en cache ne devienne obsolète :

    useQuery({
      queryKey: ["products"],
      queryFn: getProducts,
      staleTime: 300000,
    });
    

    L’interface peut afficher immédiatement les données en cache, avec React Query qui les met à jour discrètement en arrière-plan si nécessaire. Les entrées en cache sont conservées et finissent par être collectées selon les paramètres que vous définissez.

    Exemple concret

    Prenons l’écran de la liste des produits d’une application e-commerce.

    Sans cache, l’ouverture de cet écran signifie :

    Open Products
    ↓
    Network Request
    ↓
    Navigate Back
    ↓
    Open Products Again
    ↓
    Network Request
    

    Avec React Query, le même processus devient :

    Open Products
    ↓
    Network Request
    ↓
    Navigate Back
    ↓
    Open Products Again
    ↓
    Instant Cached Data
    

    La différence est que l’application semble nettement plus réactive pour l’utilisateur.

    Comparaison n°3 : États de chargement

    Au préalable à l’adoption de React Query, suivre les états de chargement impliquait de gérer plusieurs variables booléennes :

    const [loading, setLoading] = useState(false);
    const [refreshing, setRefreshing] = useState(false);
    const [isRetrying, setIsRetrying] = useState(false);
    

    Par la suite, une seule appel à l’hook expose tout ce qui est nécessaire :

    const {
      isLoading,
      isFetching,
      isRefetching,
    } = useQuery(...)
    

    React Query fait la distinction entre le premier chargement et tous les fetch en arrière-plan ultérieurs, ce qui rend la logique de l’interface beaucoup plus simple à comprendre.

    Bénéfice réel

    Au lieu d’afficher un indicateur de chargement en plein écran à chaque fetch, l’application peut faire la différence entre :

    • Chargement initial : indicateur de chargement en plein écran
    • Mise à jour en arrière-plan : un indicateur de chargement petit et discret
    • Données déjà mémorisées : aucune interruption visible du tout

    Cela donne l’impression à l’utilisateur que l’application est bien plus réactive.

    Comparaison n°4 : Support hors ligne

    Le comportement hors ligne est l’un de ces aspects que les équipes ont tendance à sous-estimer.

    Gérer cela manuellement se fait généralement comme suit :

    Check Connectivity
    Pause Requests
    Retry Later
    Handle Errors
    Refetch On Reconnect
    

    Cela signifie que de la logique de connexion personnalisée est dispersée dans l’ensemble du code.

    React Query propose plutôt une gestion intégrée en ligne et hors ligne, ainsi qu’une fonction de rechargement qui réagit aux événements de réconnexion. Dans React Native, vous pouvez l’intégrer en utilisant onlineManager conjointement avec les écouteurs d’état réseau de la plateforme.

    Par exemple :

    onlineManager.setEventListener(...)
    

    React Query peut également être configuré pour fonctionner en mode priorité hors ligne, ajustant ainsi son comportement réseau en conséquence.

    Exemple concret

    Prenons une application de lecture de nouvelles comme exemple.

    Au cours d’une journée, la connexion de l’utilisateur peut évoluer comme suit :

    • Matin : en ligne
    • Après-midi : hors ligne
    • Soir : de nouveau en ligne

    Pendant toute cette séquence, les articles précédemment stockés en cache restent lus, et dès que la connexion est rétablie, de nouveaux contenus peuvent être synchronisés automatiquement.

    Cas d’usage réels

    1. Applications de nouvelles

    Cela apporte :

    • Articles en cache
    • Mise à jour automatique en arrière-plan
    • Baisse du trafic API global
    • Possibilité de continuer à lire hors ligne

    2. Applications e-commerce

    Avantages :

    • Listes de produits en cache
    • Préchargement anticipé des catégories
    • Navigation plus rapide entre les sections
    • Expérience d’achat nettement plus fluide

    React Query permet également de précharger les données avant même que la navigation ne commence, réduisant ainsi les temps d’attente perçus.

    3. Applications de tableau de bord

    Avantages :

    • Widgets qui se mettent à jour automatiquement
    • Cache partagé entre plusieurs écrans
    • Réduction des communications réseau
    • Gestion de l’état beaucoup plus simple dans l’ensemble

    Cette approche convient particulièrement bien aux tableaux de bord analytiques et aux panneaux d’administration.

    Ce que nous avons effectivement supprimé

    Lorsque la migration a été terminée :

    Supprimé

    • Gestion personnalisée de l’état de chargement
    • Codage manuel pour les tentatives répétées
    • Appels API sortants redondants
    • Code de base pour le rafraîchissement par tirage
    • Logique de cache développée en interne
    • Gestion manuelle du rechargement

    Ajouté

    • La bibliothèque React Query elle-même
    • Clés de requête
    • Une instance QueryClient

    L’effet global : environ 500 lignes de code de gestion des API n’étaient plus nécessaires.

    Lorsque React Query peut ne pas être nécessaire

    Recourir à React Query pourrait être excessif si :

    • Votre application effectue seulement quelques appels API
    • Les données de base changent à peine
    • Le stockage en cache n’est vraiment pas nécessaire
    • Le comportement hors ligne n’a pas d’importance pour votre cas d’usage

    Cependant, pour la plupart des applications de production, les avantages finissent par l’emporter sur la courbe d’apprentissage initiale assez rapidement.

    Conclusions finales

    React Query n’est pas simplement une autre façon de récupérer des données.

    Ce outil constitue une solution complète de gestion de l’état serveur, en éliminant le code API répétitif tout en améliorant le cache, le comportement de chargement, l’efficacité réseau et l’expérience hors ligne.

    Le plus grand avantage n’était pas la performance brute.

    C’était plutôt la réduction de la complexité.

    C’est cette combinaison qui a rendu la migration intéressante.