Efectos con useEffect
💡 🎯 Al terminar esta lección podrás…
- Sincronizar un componente con el exterior con
useEffect. - Controlar cuándo se ejecuta un efecto con dependencias.
- Limpiar temporizadores y oyentes.
- Distinguir cuándo no hace falta un efecto.
1.Efectos: cuando React necesita hablar con el exterior
Dibujar un componente debe ser algo puro y predecible: los mismos datos producen la misma pantalla. Pero a veces necesitas hacer cosas fuera de React: cambiar el título de la pestaña, guardar en localStorage, escuchar el teclado, iniciar un temporizador, pedir datos a internet. Esas acciones se llaman efectos secundarios y su lugar es useEffect.
| Dentro del dibujo (render) | En un efecto (useEffect) |
|---|---|
| Calcular el JSX a partir de props y estado | Cambiar document.title |
Transformar datos (map, filter) | Leer/escribir localStorage |
| Decidir qué mostrar | Crear temporizadores y suscripciones |
| No debe tener efectos secundarios | Pedir datos a un servidor |
📌 Nota · Cuándo se ejecuta
React ejecuta el efecto después de dibujar el componente en pantalla. En el ejemplo, cada vez que cambia cuenta, el componente se vuelve a dibujar y el efecto corre otra vez (míralo en la consola).
2.El arreglo de dependencias
Ejecutar el efecto en cada dibujo casi nunca es lo que quieres. El segundo argumento de useEffect es un arreglo de dependencias que controla cuándo se vuelve a ejecutar:
| Escribes | El efecto se ejecuta… | Úsalo para |
|---|---|---|
useEffect(fn) | Después de cada dibujo | Casi nunca |
useEffect(fn, []) | Una sola vez, al aparecer el componente | Configuración inicial, suscripciones |
useEffect(fn, [a, b]) | Al aparecer y cuando cambie a o b | Sincronizar con unos datos concretos |
⚠️ Importante · Declara todo lo que usas
Incluye en el arreglo todas las variables de props o estado que el efecto lee. Si te falta alguna, el efecto trabajará con valores viejos. Los linters de React (eslint-plugin-react-hooks) te avisan de ello; hazles caso.
3.La función de limpieza
Algunos efectos dejan algo funcionando: un temporizador, un oyente de eventos. Si no los detienes, se acumulan. Para eso el efecto puede devolver una función de limpieza, que React ejecuta antes de repetir el efecto y cuando el componente desaparece.
- Al aparecer
Reloj, el efecto inicia el intervalo. - Cada segundo
setSegundos(s => s + 1)actualiza el estado. - Al ocultarlo, React ejecuta la limpieza y detiene el intervalo (míralo en la consola).
💡 Consejo · Oyentes de eventos
El patrón es idéntico para window.addEventListener("resize", fn): añade el oyente en el efecto y quítalo con removeEventListener en la limpieza. Así nunca duplicas oyentes.
4.Ejemplo útil: guardar en localStorage
Un uso muy habitual es persistir datos para que sobrevivan a recargar la página. Se hace en dos pasos: leer al empezar (con un valor inicial calculado una sola vez) y guardar con un efecto cada vez que cambia el dato.
📌 Nota · El estado inicial perezoso
useState(() => …) con una función hace que el cálculo (aquí, leer localStorage) se ejecute solo la primera vez. Si escribieras useState(localStorage.getItem("nota")), se leería en cada dibujo aunque el resultado se ignore.
📌 Nota · Sobre estos editores
Dentro de las lecciones el localStorage es una copia temporal de la página, así que la nota se pierde al pulsar Ejecutar o recargar. En un proyecto real en tu navegador sí persiste.
5.Cuándo NO usar un efecto
useEffect es un recurso para sincronizar con el exterior, no para todo. El error más común de quien empieza es usarlo para calcular datos que ya se pueden deducir:
const [precio, setPrecio] = useState(10);
const [cantidad, setCantidad] = useState(2);
const [total, setTotal] = useState(0);
useEffect(() => {
setTotal(precio * cantidad); // dibuja dos veces cada cambio
}, [precio, cantidad]);
const [precio, setPrecio] = useState(10);
const [cantidad, setCantidad] = useState(2);
const total = precio * cantidad; // valor derivado
| Situación | Qué usar |
|---|---|
| Dato que sale de otros datos (total, filtrado) | Una variable normal calculada al dibujar |
| Respuesta a un clic o un envío | El manejador de eventos (onClick, onSubmit) |
| Reiniciar estado cuando cambia una prop | Una key distinta en el componente |
| Sincronizar con algo externo (título, red, temporizador) | useEffect |
💡 Consejo · Pregúntate
«¿Esto ocurre porque algo se mostró o porque el usuario hizo algo?». Lo segundo va en un manejador de eventos. Solo lo primero necesita un efecto.
6.Un detalle: el modo estricto en desarrollo
En los proyectos creados con Vite, main.jsx envuelve la aplicación en <StrictMode>. En desarrollo, React ejecuta cada efecto dos veces (monta, limpia y vuelve a montar) para ayudarte a descubrir efectos sin limpieza. En producción solo se ejecuta una vez.
Si ves un mensaje duplicado en la consola de tu proyecto, no es un error: es React comprobando que tu limpieza funciona. Si tu efecto está bien escrito, no notarás ninguna diferencia.
7.Errores frecuentes
- Olvidar el arreglo de dependencias: el efecto corre en cada dibujo (y puede provocar bucles infinitos si actualiza estado).
- Dependencias incompletas: el efecto usa valores viejos. Incluye todo lo que lees.
- No limpiar temporizadores y oyentes: se acumulan y causan fugas de memoria.
- Usar un efecto para calcular datos derivados: calcúlalos al dibujar.
- Actualizar estado dentro de un efecto sin dependencias:
useEffect(() => setN(n + 1))crea un bucle infinito. - Marcar el efecto como
async:useEffect(async () => …)no está permitido; define una funciónasyncdentro y llámala (lo verás en la lección 10). - Poner una función nueva en las dependencias sin necesidad (cambia en cada dibujo): mueve la función dentro del efecto o usa
useCallback.
📒 Apuntes para llevar
useEffectsirve para sincronizar con el exterior: título,localStorage, temporizadores, red.- Se ejecuta después de dibujar.
- Dependencias: ninguna (cada dibujo),
[](una vez) o[a, b](cuando cambian). - Incluye en el arreglo todo lo que el efecto lee.
- Devuelve una función de limpieza para detener temporizadores y oyentes.
useState(() => …)calcula el valor inicial una sola vez.- No uses efectos para datos derivados ni para responder a clics.
- En desarrollo,
StrictModeejecuta los efectos dos veces para detectar limpiezas incorrectas.
8.Glosario
| Término | Significado |
|---|---|
| Efecto secundario | Acción que afecta algo fuera del componente: red, título, almacenamiento, temporizadores. |
useEffect | Hook que ejecuta código después de dibujar y lo sincroniza con unas dependencias. |
| Dependencias | Valores que, al cambiar, vuelven a ejecutar el efecto. |
| Limpieza | Función que devuelve el efecto para deshacer lo que hizo. |
| Estado inicial perezoso | Pasar una función a useState para calcular el valor inicial solo una vez. |
StrictMode | Modo de desarrollo que repite renders y efectos para destapar errores. |
🧠 Comprueba lo aprendido
Elige una respuesta en cada pregunta. Verás al instante si acertaste y por qué.
¿Cuándo corre useEffect(fn, [])?
Con un arreglo vacío no depende de nada, así que solo se ejecuta al montar.
¿Para qué sirve la función que devuelve un efecto?
React la ejecuta antes de repetir el efecto y al desmontar el componente.
Quieres mostrar precio * cantidad. ¿Qué es lo correcto?
Si un dato se deduce de otros, no necesita estado ni efecto.
¿Qué ocurre con useEffect(() => setN(n + 1)) sin dependencias?
Cada dibujo ejecuta el efecto, que cambia el estado, que provoca otro dibujo…
¿Qué hace useState(() => localStorage.getItem("x"))?
La función inicial se ejecuta una única vez.
Tu progreso se guarda en este navegador y se refleja en el índice del curso.
💡 🚀 ¡Ahora te toca!
La práctica fija lo aprendido. Pasa al ejercicio de esta lección.