useEffect Básico y Ciclo de Vida
Volver a clases
Frontend DevelopmentPrincipiante

useEffect Básico y Ciclo de Vida

120 min

Entender efectos secundarios, dependencias y limpieza correcta en React.

Qué es un efecto secundario

Un componente de React tiene un trabajo: recibir datos y devolver JSX. Puro, predecible, sin sorpresas. Todo lo demás —pedir datos a una API, arrancar un temporizador, suscribirse a un evento, escribir en localStorage— es un efecto secundario: algo que pasa fuera de ese cálculo y que toca el mundo exterior.

useEffect es la puerta oficial para esas operaciones. Corre después de que la pantalla se pintó, para no bloquear el render.

El modelo mental correcto: sincronización, no "ciclo de vida"

Vas a leer en muchos tutoriales que useEffect "reemplaza a los métodos de ciclo de vida". Es una traducción heredada de React con clases, y te va a llevar a bugs. El modelo que funciona es otro:

useEffect sirve para sincronizar tu componente con algo externo. No pienses "cuándo se ejecuta"; piensa "con qué se tiene que mantener sincronizado".

Con esa lente, el array de dependencias deja de ser un misterio: contiene todo aquello con lo que te sincronizas. Si el efecto usa usuarioId, entonces depende de usuarioId. Punto.

Cuándo NO necesitas useEffect

Este es el hook más sobreutilizado de React, y la IA lo mete en todos lados. Antes de escribir uno, descarta estos tres casos:

1. Datos que se pueden calcular — si se derivan de props o estado, se calculan en el render:

jsx
1// ❌ estado duplicado + efecto innecesario (y un render de más)
2const [total, setTotal] = useState(0);
3useEffect(() => { setTotal(items.reduce((a, i) => a + i.precio, 0)); }, [items]);
4
5// ✅ se calcula y ya
6const total = items.reduce((a, i) => a + i.precio, 0);

2. Responder a un evento del usuario — eso va en el manejador del evento, no en un efecto. Si algo pasa "cuando el usuario hace clic", su lugar es onClick.

3. Transformar datos para mostrarlos — filtrar, ordenar o formatear se hace en el render.

La regla: useEffect es para hablar con el mundo exterior (red, temporizadores, APIs del navegador, suscripciones). Si no sales de React, probablemente no necesitas un efecto.

El array de dependencias, sin mentiras

jsx
1useEffect(() => { /* ... */ });              // sin array: en CADA render 🚨
2useEffect(() => { /* ... */ }, []);          // solo al montar
3useEffect(() => { /* ... */ }, [usuarioId]); // al montar y cuando usuarioId cambie

El error clásico no es olvidar el array: es mentir en él. Un efecto que usa query pero declara [] funciona en la demo y luego se queda congelado con datos viejos — el bug más difícil de rastrear del semestre, porque nada truena.

Regla honesta: todo valor del componente que el efecto lea debe estar en el array. Si eso provoca que el efecto corra demasiado, el problema no es el array — es el diseño del efecto.

Y el opuesto: sin array el efecto corre en cada render. Si además hace setState, provocas un bucle infinito de renders.

Cleanup: "¿y esto quién lo apaga?"

Es la misma pregunta que te hiciste en la clase de DOM con el setInterval que nunca se detenía — ahora con el mecanismo oficial para responderla. Lo que retornes del efecto es la función de limpieza:

jsx
1useEffect(() => {
2  const id = setInterval(() => setSegundos((s) => s + 1), 1000);
3
4  return () => clearInterval(id);   // ← React la llama al desmontar
5}, []);

React ejecuta esa función en dos momentos: antes de volver a correr el efecto (cuando cambia una dependencia) y al desmontar el componente. Por eso limpia tanto las repeticiones como las fugas.

Todo lo que se registra necesita historia de limpieza:

RegistrasLimpias con
setInterval / setTimeoutclearInterval / clearTimeout
addEventListenerremoveEventListener
Suscripción a un serviciosu método unsubscribe / remove
Petición en vuelouna bandera de cancelación o AbortController

Si tu efecto no registra nada (por ejemplo, solo escribe en localStorage), no necesita cleanup. La pregunta se hace siempre; la respuesta a veces es "nada".

Los tres errores que verás en código generado

  1. Dependencias mentirosas — usa query, declara []. Síntoma: datos viejos que no se actualizan.
  2. Sin cleanup — el temporizador, listener o petición sigue vivo tras salir de la pantalla. Síntoma: la app se pone lenta con el uso, o la advertencia de "setState en componente desmontado".
  3. Efecto innecesario — sincroniza estado con estado. Síntoma: renders de más y dos fuentes de verdad que se desincronizan.

Los tres aparecen en la Auditoría IA #3 de esta misma clase. Ahora ya sabes qué buscar.

Ejemplos de Código

3 ejemplos

Efecto en cada render

javascript
1import { useState, useEffect } from "react";
2
3function Contador() {
4  const [count, setCount] = useState(0);
5
6  useEffect(() => {
7    console.log("Renderizado");
8  });
9
10  return <button onClick={() => setCount(count + 1)}>{count}</button>;
11}

Effect con dependencias

javascript
1import { useState, useEffect } from "react";
2
3function Titulo() {
4  const [visitas, setVisitas] = useState(0);
5
6  useEffect(() => {
7    document.title = `Visitas: ${visitas}`;
8  }, [visitas]);
9
10  return <button onClick={() => setVisitas((v) => v + 1)}>Sumar</button>;
11}

Limpieza de intervalos

javascript
1import { useState, useEffect } from "react";
2
3function Reloj() {
4  const [segundos, setSegundos] = useState(0);
5
6  useEffect(() => {
7    const id = setInterval(() => {
8      setSegundos((s) => s + 1);
9    }, 1000);
10
11    return () => clearInterval(id);
12  }, []);
13
14  return <div>Segundos: {segundos}</div>;
15}

Recursos

4 recursos disponibles

¡Hora de Practicar!

PrácticaPrincipiante15 min🟡 IA con bitácora

Práctica guiada - Título y localStorage

Práctica

Actualizar el document.title con contador y persistir el nombre del usuario en localStorage.

Desafío de Código

EjercicioPrincipiante15 min🔴 Sin IA

Ejercicios - useEffect básico

Ejercicios

(1) Timer con start/stop, (2) listener de resize, (3) contador con título dinámico.

Documentación Oficial

DocumentaciónPrincipiante15 min

useEffect Hook

Referencia oficial de `useEffect` y buenas prácticas.

Reto de Lectura

Reto de LecturaPrincipiante90 min🟢 IA requerida

Auditoría IA #3 — La feature completa (para TU proyecto)

La auditoría final y la más real: genera con IA una feature completa para tu proyecto integrador, audítala con todo lo aprendido, y solo entonces intégrala. Así vas a trabajar siempre.

Las dos auditorías anteriores fueron ejercicios. Esta es real: la feature que audites hoy puede terminar integrada en tu proyecto integrador. Estás haciendo exactamente lo que harás en tu trabajo.

Paso 1 — Elige y genera (15 min). Pídele a tu IA UNA feature que tu proyecto necesite. Sugerencias si no sabes cuál:

  • Barra de búsqueda con filtrado sobre tus datos (con debounce)
  • Formulario de alta con validación y mensajes de error
  • Carga de datos de tu API con estados de loading / error / vacío

Dale contexto real: cómo se llaman tus componentes, qué forma tienen tus datos. Un prompt con contexto produce código integrable; uno genérico produce un ejemplo de juguete.

Paso 2 — Auditoría completa (45 min). Esta checklist acumula TODO el semestre:

#CapaRevisa
1HTML (S1-3)¿Semántica? ¿Labels en inputs? ¿Botones reales?
2Estado (S13-14)¿Muta estado o construye versiones nuevas? ¿Keys estables o index?
3useEffect¿El array de dependencias está completo y es honesto? ¿Falta el cleanup (el "¿y esto quién lo apaga?" de la semana 9)?
4Async (S11-12)Si hay fetch: ¿race condition si el usuario teclea rápido? ¿Errores visibles o tragados? ¿Estado de loading?
5Integración¿Usa TUS nombres y estructura o inventó un mundo paralelo que no encaja en tu proyecto?
6SabotajeCórrelo. Teclea rapidísimo. Envía el form vacío. Corta la red (DevTools → Network → Offline). ¿Sobrevive?

Paso 3 — Informe + integración (30 min, entregable): (a) el prompt con contexto que usaste, (b) mínimo 4 hallazgos con línea y escenario, (c) la versión corregida, (d) veredicto de integración: la integras a tu proyecto (commit con mensaje integra búsqueda auditada, corrige X y Y) o la rechazas explicando por qué. Ambos veredictos valen la nota completa si están argumentados.