React 19 de Cero a Experto / Efectos y ciclo de vida
Cleanup: limpiar lo que un efecto abre
Un efecto que ABRE algo —un temporizador, una suscripción, un listener— tiene que poder CERRARLO.
Si no, cada vez que el efecto se repite abres otro sin cerrar el anterior: dos timers, tres, diez
—una fuga que hace que tu contador salte de a saltos o que la memoria se infle—. React resuelve
esto con la función de limpieza (cleanup): lo que devuelves desde un efecto. Hoy dominas el
ciclo de vida completo de un efecto y por qué el cleanup es obligatorio, no opcional.
Lo que abres, ciérralo
Un temporizador con su limpieza
Si arrancas un setInterval en un efecto sin limpiarlo, cada re-ejecución del efecto abre OTRO
intervalo encima. La función que DEVUELVES desde el efecto es el cleanup:
Cuando corriendo cambia, React primero llama al cleanup del efecto anterior (clearInterval(id))
y LUEGO ejecuta el efecto de nuevo. Así nunca hay dos intervalos vivos. Prueba a quitar el
return () => clearInterval(id): al pausar y reanudar varias veces, el contador empezaría a
saltar de a 2, 3, 4 por segundo —cada intervalo huérfano sumando por su cuenta—. El cleanup es
lo que mantiene UN solo temporizador.
El ciclo de vida de un efecto
El patrón suscripción
El caso clásico fuera de los timers: suscribirte a un evento del navegador (o a un store como los del SC-02) y desuscribirte en el cleanup:
useEffect(() => {
function alCambiarTamano() {
setAncho(window.innerWidth);
}
// ABRIR: suscribirse
window.addEventListener("resize", alCambiarTamano);
// CERRAR: la MISMA referencia de función (como en el SC-02, M08)
return () => window.removeEventListener("resize", alCambiarTamano);
}, []); // [] = suscribir una vez al montar, desuscribir al desmontarFíjate en el []: nos suscribimos una vez (al montar) y nos desuscribimos una vez (al desmontar).
Y el cleanup usa la MISMA referencia de función que pasamos a addEventListener —justo la regla
de removeEventListener del SC-02—. Sin el cleanup, si este componente se monta y desmonta varias
veces (navegando por la app), acumularías listeners fantasma escuchando por siempre.
¿Cuándo llama React a la función de limpieza que devuelves desde un useEffect?
Mini-reto
Practica el ciclo completo: 1) haz un componente Reloj que en un useEffect con [] arranque
un setInterval que guarde la hora actual (new Date().toLocaleTimeString()) en un estado cada
segundo, con su clearInterval en el cleanup; 2) en el App, un botón que monte/desmonte el
Reloj (con un booleano y un ternario); 3) agrega un console.log("montado") en el efecto y
console.log("limpiado") en el cleanup, y observa la pareja perfecta al mostrar/ocultar el reloj.
Qué sigue
Ya usas efectos con limpieza. Pero aquí viene la lección más importante del módulo —y la que más
código malo evita—: MUCHOS efectos que la gente escribe NO deberían existir. Sincronizar estado
con estado, transformar datos, responder a un clic… nada de eso necesita useEffect. La próxima
lección te enseña cuándo NO usar un efecto, que es tan valioso como saber usarlo.