TechLead

Hook useEffect

Efectos secundarios, obtencion de datos y gestion del ciclo de vida

Que es useEffect?

useEffect te permite realizar "efectos secundarios" en componentes funcionales. Los efectos secundarios son operaciones que afectan algo fuera del componente: obtener datos, suscripciones, manipulacion manual del DOM, etc.

Sintaxis Basica

import { useEffect, useState } from 'react';

function Componente() {
  const [datos, setDatos] = useState(null);

  // Se ejecuta despues de cada renderizado
  useEffect(() => {
    console.log('Componente renderizado');
  });

  // Se ejecuta solo en el montaje (array vacio)
  useEffect(() => {
    console.log('Componente montado');
  }, []);

  // Se ejecuta cuando cambia una dependencia
  useEffect(() => {
    console.log('datos cambio:', datos);
  }, [datos]);

  return <div>{datos}</div>;
}

Obteniendo Datos

function ListaUsuarios() {
  const [usuarios, setUsuarios] = useState([]);
  const [cargando, setCargando] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const obtenerUsuarios = async () => {
      try {
        const respuesta = await fetch('https://api.ejemplo.com/usuarios');
        if (!respuesta.ok) throw new Error('Error al obtener datos');
        const datos = await respuesta.json();
        setUsuarios(datos);
      } catch (err) {
        setError(err.message);
      } finally {
        setCargando(false);
      }
    };

    obtenerUsuarios();
  }, []); // Array vacio = solo al montar

  if (cargando) return <p>Cargando...</p>;
  if (error) return <p>Error: {error}</p>;

  return (
    <ul>
      {usuarios.map(usuario => (
        <li key={usuario.id}>{usuario.nombre}</li>
      ))}
    </ul>
  );
}

Funcion de Limpieza

function Temporizador() {
  const [segundos, setSegundos] = useState(0);

  useEffect(() => {
    const intervalo = setInterval(() => {
      setSegundos(s => s + 1);
    }, 1000);

    // Funcion de limpieza - se ejecuta al desmontar
    return () => {
      clearInterval(intervalo);
    };
  }, []);

  return <p>Segundos: {segundos}</p>;
}

// Limpieza con suscripciones
function EstadoConexion() {
  const [enLinea, setEnLinea] = useState(navigator.onLine);

  useEffect(() => {
    const handleOnline = () => setEnLinea(true);
    const handleOffline = () => setEnLinea(false);

    window.addEventListener('online', handleOnline);
    window.addEventListener('offline', handleOffline);

    return () => {
      window.removeEventListener('online', handleOnline);
      window.removeEventListener('offline', handleOffline);
    };
  }, []);

  return <p>{enLinea ? 'En linea' : 'Desconectado'}</p>;
}

Dependencias

function BusquedaUsuario({ idUsuario }) {
  const [usuario, setUsuario] = useState(null);

  useEffect(() => {
    // Se ejecuta cuando idUsuario cambia
    const obtenerUsuario = async () => {
      const respuesta = await fetch(`/api/usuarios/${idUsuario}`);
      const datos = await respuesta.json();
      setUsuario(datos);
    };

    if (idUsuario) {
      obtenerUsuario();
    }
  }, [idUsuario]); // Dependencia: idUsuario

  return usuario ? <div>{usuario.nombre}</div> : null;
}

Reglas de useEffect

  • Incluye todas las dependencias: Valores usados dentro del efecto
  • Limpia efectos: Retorna una funcion de limpieza cuando sea necesario
  • Evita loops infinitos: No actualices estado que esta en las dependencias sin condiciones

⚠️ Modo Estricto: Doble Ejecución en Desarrollo

En React 18+, Modo Estricto intencionalmente ejecuta tus efectos dos veces en desarrollo para ayudar a encontrar errores de limpieza faltante. Esto no sucede en producción.

Si tu efecto se ejecuta dos veces y causa problemas, significa que te falta una función de limpieza. Arregla la limpieza en lugar de eliminar Modo Estricto.

💡 Recomendación de Obtención de Datos

Para producción, no uses useEffect + fetch directamente. En su lugar, usa una librería de obtención de datos:

  • TanStack Query (React Query) — Caché, reintento automático, revalidación en segundo plano
  • SWR — Ligero stale-while-revalidate de Vercel
  • Componentes de Servidor — Obtención de datos en el servidor sin hooks (Next.js App Router)

Estas librerías manejan condiciones de carrera, caché, deduplicación y reintentos — problemas que son sorprendentemente difíciles de resolver correctamente a mano.