Lo reactivo y lo que sólo se lee
Mi efecto se reconecta cada vez que cambia algo que ni siquiera usa. ¿Por qué?
Al terminar vas a poder explicar
- Separar la lógica reactiva de la que sólo lee el valor más reciente
- Explicar por qué sacar una dependencia del array casi siempre es la respuesta equivocada
- Usar el patrón de la ref para valores que no deben disparar el efecto
Este efecto se conecta a una sala de chat. También quiere mostrar un aviso con el tema visual actual. Y se reconecta cada vez que el usuario cambia de tema, que no tiene absolutamente nada que ver.
1function Chat({ sala, tema }) {2 useEffect(() => {3 const conexion = conectar(sala);4 conexion.on("conectado", () => mostrarAviso("¡Conectado!", tema));5 conexion.abrir();6 return () => conexion.cerrar();7 }, [sala, tema]); // ⚠️ cambiar de tema corta la conexión8}La tentación es obvia: sacar tema del array. El linter se queja, le ponés un eslint-disable y seguís. Y ahí acabás de introducir un bug distinto: el aviso va a mostrar para siempre el tema que había cuando se creó el efecto.
Un efecto mezcla dos clases de lógica
El problema no es el array de dependencias. Es que ese efecto hace dos cosas distintas:
- Lógica reactiva — conectarse a la sala. Si la sala cambia, hay que desconectarse y volver a conectarse. Depende de
salade verdad. - Lógica no reactiva — mostrar el aviso con el tema. Quiere el valor más reciente de
tema, pero cambiarlo no debería re-ejecutar nada.
El array de dependencias sólo sabe expresar una de las dos. Por eso cualquier respuesta que se limite a agregar o sacar entradas está condenada: la pregunta está mal planteada.
La salida: separar las dos partes
React tiene una propuesta para esto — useEffectEvent — que a la fecha sigue en canal experimental. La idea es marcar explícitamente la parte no reactiva:
1function Chat({ sala, tema }) {2 // Siempre ve los valores más recientes, pero NO es una dependencia.3 const alConectar = useEffectEvent(() => {4 mostrarAviso("¡Conectado!", tema);5 });6 7 useEffect(() => {8 const conexion = conectar(sala);9 conexion.on("conectado", () => alConectar());10 conexion.abrir();11 return () => conexion.cerrar();12 }, [sala]); // ✓ y el linter está de acuerdo13}Mientras tanto: el patrón de la ref
Hasta que sea estable, se consigue lo mismo con una ref. Es exactamente lo que hace useEffectEvent por dentro:
1function Chat({ sala, tema }) {2 const temaRef = useRef(tema);3 4 // Se mantiene al día en cada render, sin disparar nada.5 useEffect(() => {6 temaRef.current = tema;7 });8 9 useEffect(() => {10 const conexion = conectar(sala);11 conexion.on("conectado", () => mostrarAviso("¡Conectado!", temaRef.current));12 conexion.abrir();13 return () => conexion.cerrar();14 }, [sala]);15}Volvé a leer la lección de useRef si esto te sorprende: una ref es una caja estable sin cola de updates. Mutarla no agenda trabajo — que es exactamente lo que necesitamos. Leerla dentro de un callback que corre después del render nos da el valor más reciente sin haberlo puesto en las dependencias.
Cómo decidir, en una pregunta
Para cada valor que usás dentro de un efecto, preguntate:
Si este valor cambia y nada más cambia, ¿tendría que desconectarse y volver a conectarse?
- Sí — es reactivo. Va en el array de dependencias, sin discusión.
- No — es no reactivo. Sacalo del efecto y leelo a través de una ref o de un effect event.
Antes de seguir · predecí
Un efecto abre una conexión a `salaId` y, al conectar, registra el evento con el `planDelUsuario` para analítica. ¿Qué va en las dependencias?
Lo que te llevás
Un efecto puede mezclar lógica reactiva con lógica que sólo lee el último valor. El array de dependencias sólo expresa la primera. Cuando una dependencia te sobra, la respuesta nunca es editar la lista: es sacar esa parte del efecto.
Antes de marcarla, comprobá
- ¿Podés explicar separar la lógica reactiva de la que sólo lee el valor más reciente?
- ¿Podés explicar explicar por qué sacar una dependencia del array casi siempre es la respuesta equivocada?
- ¿Podés explicar usar el patrón de la ref para valores que no deben disparar el efecto?