useEffectEvent y lógica no reactiva en React | Nicolás Garzón
A veces un effect debe reaccionar a una dependencia, pero necesita leer otros valores recientes sin reiniciar la sincronización.
TypeScript
Copiar const onConnected = useEffectEvent ( ( ) => {
showNotification ( "Conectado" , theme) ;
} ) ;
useEffect ( ( ) => {
const connection = createConnection ( roomId) ;
connection. on ( "connected" , onConnected) ;
connection. connect ( ) ;
return ( ) => connection. disconnect ( ) ;
} , [ roomId] ) ; El cambio de theme actualiza lo que lee el evento, pero no reconecta la sala.
Un Effect Event se llama desde effects o callbacks creados por ellos. No representa un evento directo del usuario.
No muevas dependencias realmente reactivas a un Effect Event para impedir que el effect se actualice.
Decláralo cerca del effect.
No lo pases arbitrariamente a otros componentes.
No lo uses durante render.
Convertir toda función del effect en Effect Event.
Ocultar roomId aunque sí define la conexión.
Confundirlo con useCallback.
Separa la parte reactiva que inicia la sincronización de la lógica no reactiva que necesita leer valores recientes.
Un effect puede contener dos tipos de lógica:
Reactiva: define cuándo debe reiniciarse la sincronización.
No reactiva: responde a un evento de esa sincronización y necesita leer valores actuales.
TypeScript
Copiar function Chat ( { roomId, theme } : Props) {
const onConnected = useEffectEvent ( ( ) => {
showNotification ( ` Conectado a ${ roomId} ` , theme) ;
} ) ;
useEffect ( ( ) => {
const connection = createConnection ( roomId) ;
connection. on ( "connected" , onConnected) ;
connection. connect ( ) ;
return ( ) => connection. disconnect ( ) ;
} , [ roomId] ) ;
} roomId define qué conexión existe. theme solo afecta cómo se presenta la notificación cuando ocurre el evento.
Un patrón anterior guardaba el último callback en una ref. Puede funcionar, pero oculta la intención y requiere actualización manual. useEffectEvent expresa que la función pertenece al effect, no es reactiva y siempre lee valores actuales.
TypeScript
Copiar < button onClick= { handleBuy} > Comprar< / button> Una interacción directa continúa usando un event handler normal. Effect Events se invocan desde effects o callbacks registrados por ellos, como eventos de socket, timers u observers.
Incorrecto conceptualmente:
TypeScript
Copiar const connectNow = useEffectEvent ( ( ) => connect ( roomId) ) ;
useEffect ( ( ) => connectNow ( ) , [ ] ) ; La conexión sí depende de roomId; moverla oculta el ciclo correcto. El effect quedaría conectado a una sala antigua.
Declara el Effect Event cerca del effect que lo usa.
No lo pases como prop a componentes arbitrarios.
No lo llames durante render.
No lo añadas al array de dependencias.
Mantén pequeña la parte no reactiva.
Estas restricciones evitan convertirlo en un mecanismo global de callbacks “siempre actuales”.
TypeScript
Copiar function Metrics ( { enabled, intervalMs, filters } : Props) {
const collect = useEffectEvent ( ( ) => {
sendMetrics ( filters) ;
} ) ;
useEffect ( ( ) => {
if ( ! enabled) return ;
const id = window. setInterval ( collect, intervalMs) ;
return ( ) => window. clearInterval ( id) ;
} , [ enabled, intervalMs] ) ;
} Cambiar filtros modifica qué lee la siguiente captura, sin reiniciar el intervalo. Cambiar intervalMs sí recrea el timer porque define su configuración.
Para evitar entender exhaustive-deps.
Para funciones compartidas entre componentes.
Para cálculos puros durante render.
Para callbacks de usuario.
Cuando el valor sí debe reiniciar setup/cleanup.
Pregunta por cada valor leído:
¿Si cambia, el sistema externo anterior queda inválido?
¿O solo necesito el valor actual cuando ocurra un callback?
El primer grupo son dependencias. El segundo puede pertenecer a un Effect Event.
useEffectEvent depende de una versión compatible de React y del plugin actualizado de Hooks. En librerías o proyectos con versiones anteriores, documenta el requisito y no asumas disponibilidad universal.
Un Effect Event lee props y state actuales sin volver reactiva esa lectura.
Solo separa lógica no reactiva dentro de una sincronización.
No es useCallback, ref ni handler de usuario.
Las dependencias que definen setup deben permanecer en el effect.
¿Por qué theme puede vivir en un Effect Event de notificación?
¿Por qué roomId debe seguir como dependencia?
¿En qué se diferencia de useCallback?
¿Dónde debe llamarse un Effect Event?
Ver respuestas
Porque cambia la presentación del callback, no la conexión existente.
Porque determina qué recurso está sincronizado.
useCallback estabiliza identidad según dependencias; Effect Event siempre lee valores actuales y no es reactivo.
Desde un effect o callbacks creados por esa sincronización.
Refs como prop y useImperativeHandle cubre otra salida controlada para integrar capacidades imperativas.