El hook useEffect
Introducción
useEffect es un hook en React que permite realizar efectos secundarios en los componentes funcionales. Los efectos secundarios incluyen cosas como:
- Llamadas a APIs.
- Suscripción a eventos.
- Actualización del DOM.
- Limpieza de recursos (como eliminar un
setInterval).
1. Cómo funciona useEffect? #
useEffect se ejecuta después de que el componente se renderice. React ejecuta el código dentro de useEffect cada vez que se cumplen las condiciones que definimos.
Ejemplo básico #
1import React, { useState, useEffect } from "react"; 2 3function Contador() { 4 const [contador, setContador] = useState(0); 5 6 useEffect(() => { 7 console.log("El componente se renderizó o el contador cambió"); 8 }); 9 10 return ( 11 <div> 12 <p>Has hecho clic {contador} veces</p> 13 <button onClick={() => setContador(contador + 1)}>Incrementar</button> 14 </div> 15 ); 16} 17 18export default Contador;
Explicación #
useEffectse ejecuta después de cada render (incluido el inicial).- Cada vez que haces clic en el botón, React renderiza el componente, y el efecto se ejecuta.
2. Dependencias en useEffect #
Podemos controlar cuándo debe ejecutarse useEffect usando el array de dependencias.
Ejemplo: Ejecutar useEffect solo una vez #
1useEffect(() => { 2 console.log("El componente se montó"); 3}, []); // <- El array vacío significa que solo se ejecutará al montar el componente
Ejemplo: Ejecutar useEffect cuando cambia una variable #
1useEffect(() => { 2 console.log("El contador cambió:", contador); 3}, [contador]); // <- Solo se ejecuta cuando 'contador' cambia
3. Limpieza en useEffect #
Si tu efecto crea algo que necesita limpieza (como un temporizador o una suscripción), debes devolver una función desde el useEffect.
Ejemplo: Temporizador #
1function Temporizador() { 2 const [segundos, setSegundos] = useState(0); 3 4 useEffect(() => { 5 const intervalo = setInterval(() => { 6 setSegundos((prev) => prev + 1); 7 }, 1000); 8 9 return () => { 10 clearInterval(intervalo); // Limpiamos el intervalo al desmontar el componente 11 }; 12 }, []); 13 14 return <p>Segundos: {segundos}</p>; 15} 16 17export default Temporizador;
Explicación #
setIntervalinicia un temporizador.- La función de limpieza
clearInterval(intervalo)se ejecuta cuando el componente se desmonta o el efecto se vuelve a ejecutar.
4. Casos Comunes de useEffect #
Llamadas a una API #
1import React, { useState, useEffect } from "react"; 2 3function ListaUsuarios() { 4 const [usuarios, setUsuarios] = useState([]); 5 6 useEffect(() => { 7 fetch("https://jsonplaceholder.typicode.com/users") 8 .then((response) => response.json()) 9 .then((data) => setUsuarios(data)); 10 }, []); // Se ejecuta solo al montar el componente 11 12 return ( 13 <ul> 14 {usuarios.map((usuario) => ( 15 <li key={usuario.id}>{usuario.name}</li> 16 ))} 17 </ul> 18 ); 19} 20 21export default ListaUsuarios;
Explicación #
fetchobtiene datos de una API.- Actualizamos el estado con
setUsuariospara mostrar los datos en la pantalla.
Suscripción a Eventos #
1function Teclado() { 2 const [tecla, setTecla] = useState(""); 3 4 useEffect(() => { 5 const manejarTecla = (e) => setTecla(e.key); 6 7 window.addEventListener("keydown", manejarTecla); 8 9 return () => { 10 window.removeEventListener("keydown", manejarTecla); // Eliminamos el evento 11 }; 12 }, []); 13 14 return <p>Tecla presionada: {tecla}</p>; 15} 16 17export default Teclado;
Explicación #
- Nos suscribimos al evento
keydownpara detectar teclas presionadas. - La función de limpieza elimina la suscripción cuando el componente se desmonta.
Sincronización con el título del documento #
1function Contador() { 2 const [contador, setContador] = useState(0); 3 4 useEffect(() => { 5 document.title = `Clics: ${contador}`; 6 }, [contador]); // Cambia el título solo cuando 'contador' cambia 7 8 return ( 9 <div> 10 <p>Has hecho clic {contador} veces</p> 11 <button onClick={() => setContador(contador + 1)}>Incrementar</button> 12 </div> 13 ); 14} 15 16export default Contador;
Explicación #
- Actualizamos el título del documento con cada cambio en el contador.
- El efecto solo se ejecuta cuando
contadorcambia, gracias al array de dependencias.
Simular Montar y Desmontar #
1function MostrarMensaje() { 2 const [mostrar, setMostrar] = useState(false); 3 4 return ( 5 <div> 6 <button onClick={() => setMostrar(!mostrar)}> 7 {mostrar ? "Ocultar" : "Mostrar"} Mensaje 8 </button> 9 {mostrar && <Mensaje />} 10 </div> 11 ); 12} 13 14function Mensaje() { 15 useEffect(() => { 16 console.log("El componente se montó"); 17 18 return () => { 19 console.log("El componente se desmontó"); 20 }; 21 }, []); 22 23 return <p>¡Hola, mundo!</p>; 24} 25 26export default MostrarMensaje;
Explicación #
- Cuando el componente
Mensajese monta, muestra un mensaje en la consola. - Cuando se desmonta (al ocultarlo), ejecuta la limpieza.
5. Consideraciones Importantes #
-
Dependencias Incorrectas
Si omites dependencias necesarias en el array, el efecto puede comportarse de forma inesperada. Usa herramientas como ESLint para detectarlo. -
Efectos en Bucles Infinitos
Si no defines el array de dependencias correctamente, el efecto puede ejecutarse continuamente.1useEffect(() => { 2 setContador(contador + 1); // Esto causará un bucle infinito 3});Solución: Asegúrate de agregar dependencias en el array o usar una función de actualización de estado.
Resumen del tema
Conceptos clave #
- Efectos Secundarios (Side Effects): operaciones que interactúan con el mundo exterior fuera del renderizado puro (APIs, timers, suscripciones, manipulación de DOM nativo).
- Array de Dependencias:
- Sin array: se ejecuta tras cada renderizado.
- Array vacío
[]: se ejecuta una sola vez tras el montaje inicial. - Con dependencias
[a, b]: se ejecuta solo cuandoaobcambian de valor.
- Función de Limpieza (Cleanup): retornar una función
return () => { ... }para liberar timers (clearInterval), desuscribir event listeners o cancelar peticiones activas.
Qué debes recordar #
useEffect sincroniza componentes con sistemas externos; define exhaustivamente sus dependencias y retorna siempre una función de limpieza para evitar fugas de memoria.