Contactez-nous

Introduction aux effets de bord (Data fetching, subscriptions, timers, mutations manuelles du DOM)

Qu'est-ce qu'un effet de bord (side effect) en React ? Découvrez les exemples courants comme le data fetching, les abonnements, les timers et la manipulation du DOM.

Qu'est-ce qu'un effet de bord en React ?

Au coeur de React se trouve l'idée de composants comme des fonctions (relativement) pures : étant donné un ensemble de props et un état, ils doivent toujours retourner la même description d'interface utilisateur (JSX). Leur rôle principal est de calculer et décrire l'UI. Cependant, une application web ne se limite pas à afficher une UI statique. Elle doit interagir avec le monde extérieur, répondre à des événements, récupérer des données distantes, etc.

Toute opération effectuée par un composant qui n'est pas directement liée au calcul de sa sortie (le JSX) est considérée comme un effet de bord (ou side effect). Ces opérations "sortent" du flux de rendu pur de React pour interagir avec des systèmes externes ou modifier un état qui n'est pas directement géré par le rendu de React. Pensez-y comme à tout ce que votre composant "fait" en plus de simplement "décrire ce qu'il faut afficher".

Il est crucial de gérer ces effets correctement car ils peuvent avoir un impact sur l'état global de l'application, les performances, et introduire des comportements inattendus s'ils ne sont pas synchronisés avec le cycle de vie du composant (par exemple, essayer de mettre à jour l'état d'un composant qui n'existe plus).

Exemples courants d'effets de bord

Voici quelques-unes des catégories les plus fréquentes d'effets de bord que vous rencontrerez dans le développement React :

  1. Récupération de données (Data Fetching) :
    C'est peut-être l'effet de bord le plus commun. Les composants ont souvent besoin d'afficher des informations qui ne sont pas disponibles localement au moment du rendu initial. Ils doivent interroger une API externe (via `fetch` ou des bibliothèques comme `axios`) pour récupérer ces données. Cette opération est asynchrone et se produit après que le composant a été rendu au moins une fois (souvent pour afficher un état de chargement).
    // Effet typique : Aller chercher des posts d'un blog
    async function fetchPosts() {
      const response = await fetch('/api/posts');
      const posts = await response.json();
      // ... puis mettre à jour l'état avec les posts
    }
    // Cet appel doit être géré comme un effet de bord.
    
  2. Abonnements (Subscriptions) :
    Votre composant peut avoir besoin de réagir à des changements provenant de sources externes qui "poussent" des informations. Cela inclut :
    • S'abonner à des messages via WebSockets pour des mises à jour en temps réel.
    • Ecouter des événements globaux du navigateur (ex: `window.addEventListener('resize', handleResize)`).
    • S'abonner à des sources de données externes (comme un store Redux en dehors du contexte React, ou des services tiers).

    L'aspect crucial des abonnements est qu'ils nécessitent généralement un nettoyage : il faut se désabonner lorsque le composant n'est plus utilisé pour éviter les fuites mémoire et les erreurs.

    // Effet typique : Ecouter le redimensionnement de la fenêtre
    function handleResize() {
      console.log('Fenêtre redimensionnée !');
    }
    window.addEventListener('resize', handleResize); // L'abonnement est un effet
    // Il faudra appeler window.removeEventListener('resize', handleResize) au nettoyage.
    
  3. Minuteurs (Timers) :
    Utiliser `setTimeout` pour exécuter une action après un délai, ou `setInterval` pour exécuter une action de manière répétée. Ces fonctions planifient des opérations en dehors du flux de rendu synchrone de React. Comme les abonnements, les minuteurs doivent être nettoyés (avec `clearTimeout` ou `clearInterval`) lorsque le composant est démonté ou que l'effet n'est plus nécessaire, pour éviter des exécutions non désirées ou des fuites.
  4. // Effet typique : Afficher un message après 3 secondes
    const timerId = setTimeout(() => {
      console.log('Message retardé !');
    }, 3000);
    // Il faudra appeler clearTimeout(timerId) au nettoyage.
    
  5. Mutations manuelles du DOM :
    React gère le DOM de manière déclarative. Normalement, vous ne devriez pas avoir besoin de manipuler le DOM directement. Cependant, il existe des cas limites :
    • Intégration avec des bibliothèques JavaScript tierces qui ne sont pas écrites pour React et qui attendent de manipuler directement des noeuds DOM.
    • Gestion manuelle du focus sur un élément d'input.
    • Mesure de la taille ou de la position d'un élément DOM après le rendu.
    • Animation directe d'éléments via l'API Web Animations.

    Ces opérations sont des effets de bord car elles interagissent directement avec une structure (le DOM) gérée par React, mais en dehors de son contrôle déclaratif habituel.

    // Effet typique : Mettre le focus sur un input au montage
    const inputElement = document.getElementById('monInput');
    if (inputElement) {
      inputElement.focus(); // Manipulation directe du DOM
    }
    // Idéalement géré via useRef et useEffect en React.
    

Pourquoi gérer les effets de bord spécifiquement ?

Exécuter ces opérations directement dans le corps d'un composant fonctionnel (c'est-à-dire pendant la phase de rendu) est généralement une mauvaise pratique. Cela peut entraîner des comportements imprévisibles, des appels d'API à chaque rendu (même inutilement), des fuites mémoire (si le nettoyage n'est pas effectué), et bloquer le rendu.

React fournit un mécanisme dédié pour isoler et gérer ces effets de bord de manière contrôlée et synchronisée avec le cycle de vie du composant : le hook `useEffect`. Ce hook permet de spécifier le code de l'effet à exécuter, quand il doit s'exécuter (par exemple, seulement après le premier rendu, ou quand certaines données changent), et comment nettoyer après lui. C'est ce que nous allons explorer en détail dans les sections suivantes.