CodeForge

React 19 de Cero a Experto / Efectos y ciclo de vida

Cleanup: limpiar lo que un efecto abre

Teoría22 min20 XP

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:

suscripcion.tsx
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 desmontar

Fí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.