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.