Accueil / Articles / Retirer le référentiel de la valeur la plus récente : Gérer les événements avec useEffectEvent

Retirer le référentiel de la valeur la plus récente : Gérer les événements avec useEffectEvent

Découvrez comment useEffectEvent dans React 19.2 sépare la logique non réactive d’un effet, élimine les astuces utilisant le ref latest-value, et indique quand cet hook n’est pas l’outil adapté.

917 mots

De nombreux projets React contiennent un useRef dont la seule fonction est de conserver « la valeur la plus récente » afin qu’un effet n’ait pas besoin d’en dépendre. Cette astuce fonctionne, mais elle cache l’intention réelle. React 19.2 a rendu useEffectEvent stable, offrant ainsi à ce schéma un hook de première classe. À la fin, vous serez en mesure de séparer la logique réactive et non réactive à l’intérieur d’un effet, et de savoir quand ce hook ne s’applique pas.

L’array de dépendances qui ne peut pas gagner

Le conflit apparaît avec des connexions à long terme : salles de chat, flux WebSocket, sessions d’analyse, abonnements. Un ChatRoom reçoit roomId et theme. L’effet doit se reconnecter lorsque roomId change, mais il ne lit theme que pour styliser un message après la connexion.

Ajoutez theme à l’array des dépendances, et le passage en mode sombre détruit inutilement le socket. Si vous l’omettez, la règle de linting des hooks se plaint ; si vous la silencez, le callback conserve theme capturé lors d’un rendu précédent, ce qui constitue un cas classique de fermeture obsolète.

function ChatRoom({ roomId, theme }) {
  useEffect(() => {
    const connection = createConnection(roomId);
    connection.on('connected', () => {
      showNotification('Connected!', theme); // stale after theme changes
    });
    connection.connect();
    return () => connection.disconnect();
  }, [roomId, theme]); // theme shouldn't trigger a reconnect
}

La solution trouvée par la plupart des équipes

La correction habituelle consistait à copier theme dans une ref à chaque rendu et à lire ref.current à l’intérieur du callback. Cela fonctionne, mais il est facile d’oublier l’étape de synchronisation, et rien dans le code n’indique que cette logique est délibérément non réactive.

Séparer la logique des événements avec useEffectEvent

useEffectEvent extrait la partie non réactive d’un effet dans sa propre fonction. Cette fonction voit toujours les dernières valeurs des props et de l’état, son appel ne réexécute jamais l’effet, et elle n’est pas incluse dans l’array des dépendances.

Au niveau suivant, la notification passe en mode onConnected. Cet effet se contente de créer la connexion, d’enregistrer le gestionnaire, de se connecter, puis de se déconnecter lors du nettoyage.

import { useEffect, useEffectEvent } from 'react';

function ChatRoom({ roomId, theme }) {
  const onConnected = useEffectEvent(() => {
    showNotification('Connected!', theme); // always fresh, never a dependency
  });

  useEffect(() => {
    const connection = createConnection(roomId);
    connection.on('connected', () => onConnected());
    connection.connect();
    return () => connection.disconnect();
  }, [roomId]); // only roomId matters now
}

Seul roomId reste comme dépendance. theme n’a pas été caché au linter ; il a simplement été reclasseé. Afficher un message de confirmation lorsqu’une connexion s’établit est une réaction à un événement, il s’agit donc de logique d’événement et non de synchronisation. Changer de thème ne rétablit plus la connexion, et le message suivant utilise toujours le thème actuel.

Conceptuellement, c’est exactement ce que faisait manuellement la manipulation avec le ref : React garde la fonction appelée depuis l’effet en pointant vers la clôture de la dernière rendu, et l’intention est désormais visible.

Avantages

  • Aucune clôture obsolète. L’Effet Événement lit les valeurs les plus récentes sans nécessiter de mises à jour manuelles du ref.
  • L’effet s’exécute uniquement lorsque une valeur avec laquelle il est réellement synchronisé change.
  • Les effets signifient « maintenir ce système en synchronisation avec cet état » ; les Effect Events signifient « effectuer ceci lorsque cela se produit ».
  • Les documents React encouragent les développeurs à séparer les événements des effets depuis l’époque de React 18 ; la version 19.2 soutient enfin ce conseil grâce à un hook stable. Pour en savoir plus sur cette version, consultez notre aperçu de Activity, useEffectEvent et rendu statique dans React 19.2.

    useEffectEvent ne remplace pas useEffect, et ce n’est pas non plus un moyen général pour réduire les tableaux de dépendances.

    • L’utilisez uniquement lorsque un changement de valeur ne doit pas redémarrer l’effet. Sinon, cette valeur doit figurer dans le tableau.
    • N’appeliez jamais un Effect Event pendant le rendu ; invoquez-le depuis l’intérieur des effets, tels que les callbacks de souscription ou les temporiseurs.
    • Gardez-le local à son composant plutôt que de le transmettre aux enfants en tant que prop.
    • Si la majeure partie d’un effet se trouve à l’intérieur d’un Effect Event, la logique devrait probablement être placée dans un gestionnaire d’événements normal.

    Au préalable de la version 19.2, ce hook n’existait que dans des versions expérimentales, donc les projets utilisant 19.0 ou 19.1 doivent être mis à jour pour utiliser l’API stable.

    Points clés

    • Toute solution de type « conserver la dernière valeur dans un ref » est un candidat pour useEffectEvent.
    • Pour chaque dépendance, demandez-vous si un changement doit redémarrer l’effet ; dans le cas contraire, le code qui la lit correspond à de la logique d’événement.
  • L’API est très compacte, mais elle donne un nom au problème que presque tous les développeurs React ont rencontré sans savoir comment le désigner.
  • Lectures complémentaires