Accueil / Articles / Comprendre les hooks personnalisés de React : réutilisation de la logique sans état partagé

Comprendre les hooks personnalisés de React : réutilisation de la logique sans état partagé

Découvrez ce qu sont les hooks personnalisés de React, comment ils extraient et partagent la logique à état entre les composants, ainsi que les erreurs courantes à éviter lors de leur création.

1281 mots

Introduction

Avez-vous déjà eu à réécrire la même paire useState et useEffect dans trois composants différents, en ne changeant que les noms des variables à chaque fois ? Presque tous les développeurs React rencontrent ce problème à un moment ou à un autre. Le code fonctionne bien, mais cela signifie que la même logique est dupliquée dans toute la base de code, et chaque copie a tendance à s’éloigner progressivement au fil du temps en étant modifiée indépendamment.

C’est précisément la situation que les hooks personnalisés dans React ont été conçus pour résoudre. Les documents React traitant de ce sujet expliquent qu’en extrayant le comportement d’un composant dans une fonction dédiée et réutilisable, différentes parties d’une application peuvent partager le même comportement à état, au lieu de copier indéfiniment l’implémentation sous-jacente. Cette partie de l’article décrit ce qu’étaient réellement les hooks personnalisés, leur fonctionnement dans du code concret, ainsi que les avantages et les pièges qu’il convient de comprendre avant de créer ses propres hooks.

Qu’est-ce que les hooks personnalisés React ?

En son essence, un hook personnalisé n’est rien de plus qu’une fonction JavaScript qui respecte une règle stricte de nommage : son nom doit commencer par use. À l’intérieur, elle peut appeler d’autres hooks tels que useState ou useEffect, et elle renvoie toutes les valeurs ou fonctions dont le composant appelant a besoin. React lui-même ne traite pas cette fonction de manière particulière en temps d’exécution — le préfixe use est purement conventionnel, mais il est essentiel, car il permet à React d’appliquer correctement les règles des hooks et aux autres développeurs de reconnaître immédiatement à quoi sert la fonction.

Hooks personnalisés vs fonctions ordinaires

Une fonction utilitaire standard peut effectuer de nombreuses tâches utiles, mais elle est empêchée d’appeler d’autres hooks car elle se trouve en dehors du mécanisme de rendu de React. Un hook personnalisé ne connaît pas cette restriction. C’est précisément son avantage : vous pouvez regrouper des comportements gérant un état — suivre un indicateur de chargement, écouter un événement du navigateur ou tout autre élément similaire — en quelque chose de réutilisable qui s’intègre parfaitement au cycle de vie des composants React.

Comment fonctionnent les hooks personnalisés de React en pratique

Un exemple concret clarifie cela bien plus rapidement que toute explication abstraite.

Extraction de la logique d’un composant

Imaginons trois composants non liés entre eux qui doivent tous détecter si le navigateur dispose actuellement d’une connexion réseau. Sans un hook partagé, chacun d’eux devrait créer sa propre configuration useState et useEffect pour surveiller cela :

function StatusBadge() {
  const [isOnline, setIsOnline] = useState(navigator.onLine);

  useEffect(() => {
    const goOnline = () => setIsOnline(true);
    const goOffline = () => setIsOnline(false);

    window.addEventListener('online', goOnline);
    window.addEventListener('offline', goOffline);

    return () => {
      window.removeEventListener('online', goOnline);
      window.removeEventListener('offline', goOffline);
    };
  }, []);

  return <span>{isOnline ? 'Online' : 'Offline'}</span>;
}

À la place, vous pouvez déplacer cette logique dans un seul hook personnalisé, et à partir de là, tout composant ayant besoin de cet état n’aura qu’à l’appeler :

function useOnlineStatus() {
  const [isOnline, setIsOnline] = useState(navigator.onLine);

  useEffect(() => {
    const goOnline = () => setIsOnline(true);
    const goOffline = () => setIsOnline(false);

    window.addEventListener('online', goOnline);
    window.addEventListener('offline', goOffline);

    return () => {
      window.removeEventListener('online', goOnline);
      window.removeEventListener('offline', goOffline);
    };
  }, []);

  return isOnline;
}

// Usage in any component:
function StatusBadge() {
  const isOnline = useOnlineStatus();
  return <span>{isOnline ? 'Online' : 'Offline'}</span>;
}

Aucun composant n’a plus besoin de configurer lui-même les écouteurs d’événements — chacun demande simplement à useOnlineStatus la valeur actuelle.

Partager la logique d’état sans partager l’état lui-même

C’est un détail qui prend par surprise de nombreux débutants : un hook personnalisé partage le comportement, pas l’état lui-même. Si deux composants distincts appellent chacun useOnlineStatus, chacun obtient sa propre copie privée de cet état. Ils suivent une logique identique, mais les valeurs réelles présentes dans chaque composant sont complètement indépendantes — il n’y a aucun état partagé ou lié entre eux.

Avantages majeurs de l’utilisation des hooks personnalisés React

  • Réutilisabilité entre composants : Une fois que la logique est intégrée dans un hook, aucun composant de l’application n’a besoin de dupliquer ne serait-ce qu’une ligne pour l’utiliser, ce qui garantit que son comportement reste cohérent partout où elle est employée.
  • Composants plus propres et plus lisibles : En extrayant la logique gérant l’état hors du composant, le code restant est largement débarrassé des problèmes liés à la gestion de l’état, ce qui permet à quiconque de le comprendre rapidement.
  • Tests plus faciles en isolation : La logique extraite peut être testée complètement séparément de tout composant qui l’utilise, ce qui signifie qu’elle n’a besoin d’être vérifiée qu’une seule fois au lieu d’être rétestée indirectement chaque fois qu’un composant consommateur change.
  • Accès à des talents expérimentés : Créer des hooks véritablement réutilisables — et non simplement de la logique renommée et copiée-collée avec un préfixe use ajouté — exige une connaissance approfondie des modèles sous-jacents de React. Les équipes qui souhaitent que cela soit géré correctement dès le début cherchent parfois en dehors de leur propre personnel des développeurs ReactJS spécialisés, dont l’expérience permet au design des hooks de rester solide même à mesure que le projet s’étend.
  • Erreurs courantes à éviter

    Même les hooks écrits avec de bonnes intentions peuvent rencontrer des problèmes de manière prévisible.

    • Violation des règles relatives aux hooks : Appeler un hook à l’intérieur d’une condition, dans une boucle, ou depuis une fonction ordinaire plutôt que depuis un composant ou un autre hook perturbe la capacité de React à maintenir l’état cohérent lors des rendus. Le résultat est généralement un bug étrange et intermittent dont il est difficile de retracer la cause.
    • Trop de fonctionnalités regroupées dans un seul hook : Intégrer la validation des formulaires, les requêtes réseau et la gestion de l’état de l’interface utilisateur dans un seul hook personnalisé rend ce dernier plus difficile à tester, à réutiliser et à comprendre que si ces mêmes responsabilités étaient réparties sur deux ou trois hooks plus petits et mieux ciblés.
  • Extraction d’une logique qui n’avait pas besoin d’être extraite : Toute appel à useState ne mérite pas forcément de devenir un hook indépendant. Si une logique n’est utilisée qu’en un seul endroit, l’extraire ne fait que rajouter une couche d’indirection sans aucun avantage réel.
  • Oublier de mémoriser lorsque c’est nécessaire :Lorsqu’un hook personnalisé renvoie des fonctions ou des objets sans les mémoriser correctement, les composants qui l’utilisent peuvent se retrouver à se rérender inutilement. Ce type de perte de performance est subtil et facile à négliger lors des tests de routine.
  • Conclusion

    Les hooks personnalisés dans React servent non seulement à éviter la répétition du code, mais ils constituent également un mécanisme efficace pour maintenir une base de code en expansion cohérente et uniforme. Une fois qu’une équipe développe l’habitude de repérer des logiques pouvant être extraites, la complexité des composants a tendance à diminuer, il devient plus facile de détecter les erreurs, et le comportement reste constant dans toute l’application, au lieu de diverger progressivement entre des composants censés fonctionner de la même manière. À mesure que les applications React gagnent en échelle et en complexité, savoir quand et comment créer un hook personnalisé solide devient une compétence de base plutôt que quelque chose réservé aux développeurs avancés.

    Si votre équipe doit gérer un code rempli de logiques redondantes et souhaite y introduire une véritable structure, il peut être utile de consulter une entreprise de développement React js qui a déjà mené des refacturations similaires sur d’autres projets à grande échelle.

    Lectures complémentaires

  • React Query et Redux : Rethinking l’état du serveur dans des applications grandes — Découvrez pourquoi une application de chat en production a utilisé TanStack Query plutôt que Redux pour gérer les données du serveur, et où Redux trouve encore sa place dans l’architecture React moderne.
  • Éviter les problèmes d’état silencieux dus à la mutation des références en JavaScript — Apprenez pourquoi muter des objets et des arrays par référence perturbe les mises à jour de React, pourquoi la fonction spread ne crée que des copies superficielles, et comment cloner en profondeur l’état de manière sûre.
  • Construire un modèle mental pour React : Reconciliation, State et Hooks — Découvrez les raisons qui sous-tendent les concepts fondamentaux de React — reconciliation, composants, props, state et hooks — afin de développer une intuition plutôt que de mémoriser des API.