Inicio / Artículos / Retirar el Referencia de Valor Más Reciente: Eventos de Efecto con useEffectEvent

Retirar el Referencia de Valor Más Reciente: Eventos de Efecto con useEffectEvent

Aprenda cómo useEffectEvent en React 19.2 separa la lógica no reactiva de un efecto, elimina los trucos con el ref latest-value y determina cuándo este hook no es la herramienta adecuada.

917 palabras

Muchos conjuntos de código de React contienen un useRef cuya única función es almacenar “el valor más reciente” para que un efecto no tenga que depender de él. Este truco funciona, pero oculta la intención real. React 19.2 hace que useEffectEvent sea estable, brindando a ese patrón un hook de primera clase. Al final, podrás separar la lógica reactiva y no reactiva dentro de un efecto, y saber cuándo el hook no es aplicable.

La matriz de dependencias que nunca gana

El conflicto surge con conexiones de larga duración: salas de chat, feeds de WebSocket, sesiones de análisis, suscripciones. Un ChatRoom recibe roomId y theme. El efecto debe reconectarse cuando roomId cambia, pero solo lee theme para aplicar un estilo a un mensaje después de conectarse.

Agregue theme al array de dependencias y al cambiar al modo oscuro se interrumpe el socket sin motivo alguno. Si no lo incluye, la regla de linting de los hooks emite una advertencia; si la silencia, la función de callback mantiene capturado el theme de una renderización anterior, lo que constituye un cierre obsoleto clásico.

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 solución temporal que adoptaron la mayoría de los equipos

La solución habitual consistía en copiar theme a una referencia en cada renderización y leer ref.current dentro de la función de callback. Funciona, pero es fácil olvidar el paso de sincronización, y nada en el código indica que la lógica sea deliberadamente no reactiva.

Separar la lógica de eventos con useEffectEvent

useEffectEvent extrae la parte no reactiva de un efecto en una función separada. Esa función siempre accede a los últimos valores de props y estado, su llamada nunca vuelve a ejecutar el efecto, y no se incluye en el array de dependencias.

A continuación, la notificación pasa a onConnected. El efecto solo crea la conexión, registra el manejador, se conecta y se desconecta al finalizar.

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
}

Solo roomId queda como dependencia. theme no se ha ocultado del analizador; simplemente se ha reclasificado. Mostrar un mensaje emergente cuando se establece una conexión es una reacción a un evento, por lo que se trata de lógica de eventos y no de sincronización. Cambiar el tema ya no vuelve a establecer la conexión, y el siguiente mensaje emergente sigue utilizando el tema actual.

Conceptualmente, esto es lo que hacía manualmente el truco con los referentes: React mantiene la función a la que se hace referencia desde el efecto apuntando a la cierre del último renderizado, y ahora la intención es clara.

Beneficios

  • Sin cierres obsoletos. El efecto de eventos lee los valores más recientes sin necesidad de actualizar manualmente los referentes.
  • Menos ejecuciones innecesarias. El efecto se activa únicamente cuando cambia un valor con el que realmente está sincronizado.
  • Un modelo mental más claro. Los efectos significan “mantener este sistema sincronizado con este estado”; los Eventos de Efecto significan “hacer esto cuando ocurra aquello”.
  • La documentación de React ha instado a los desarrolladores a separar los eventos de los efectos desde la era de React 18; 19.2 finalmente respalda ese consejo con un hook estable. Para conocer más sobre esta versión, consulte nuestro resumen de Activity, useEffectEvent y renderizado estático en React 19.2.

    Antes de usarlo

    useEffectEvent no reemplaza a useEffect, ni es una forma general de reducir las matrices de dependencias.

    • Úselo solo cuando un cambio en el valor no debe reiniciar el efecto. Si sí lo hace, ese valor debe estar en el array.
    • Nunca llame a un Effect Event durante la renderización; invoquelo desde dentro de los efectos, como en las devoluciones de llamada de suscripción o temporizadores.
    • Manténgalo local a su componente en lugar de pasarlo a los hijos como prop.
    • Si la mayor parte de un efecto termina dentro de un Effect Event, es probable que la lógica pertenezca a un manejador de eventos normal.

    Antes de la versión 19.2, el hook existía solo en versiones experimentales, por lo que los proyectos con 19.0 o 19.1 deben actualizarse para utilizar la API estable.

    Puntos clave

    • Cada solución temporal tipo “mantener el valor más reciente en un ref” es candidata para useEffectEvent.
    • Para cada dependencia, pregúntese si un cambio debe reiniciar el efecto; si no, el código que lo lee corresponde a lógica de eventos.
  • La API es muy pequeña, pero nombra un problema con el que casi todo desarrollador de React se ha encontrado sin saber cómo llamarlo.
  • Lecturas relacionadas