Kodokon kodokon.com

useEffect: efectos, dependencias, limpieza

Sincroniza tus componentes con el mundo exterior usando useEffect, dominando las dependencias y la limpieza.

9 min · 3 preguntas

Abrir esta lección en Kodokon

Un componente de React calcula JSX a partir de props y estado. Todo lo que quede fuera de ese ámbito -cambiar el título del documento, iniciar un temporizador, suscribirse a un evento del navegador- es un efecto secundario. useEffect ejecuta ese código después del renderizado, sin bloquear la visualización, y lo vuelve a sincronizar cuando ciertos valores cambian.

JSX
import { useEffect } from "react";

function CartTitle({ count }) {
  useEffect(() => {
    document.title = `Cart (${count})`;
  }, [count]);

  return <p>Items: {count}</p>;
}
El efecto solo se vuelve a ejecutar cuando count cambia.

El array de dependencias controla la frecuencia con la que se ejecuta el efecto. [count]: el efecto se vuelve a ejecutar después de cada renderizado en el que count haya cambiado. []: el efecto se ejecuta una sola vez, tras el primer renderizado. Sin array: el efecto se vuelve a ejecutar después de cada renderizado, lo que rara vez es lo que quieres. Regla de oro: todo valor del componente usado dentro del efecto debe aparecer en el array.

JSX
import { useEffect, useState } from "react";

function Timer() {
  const [seconds, setSeconds] = useState(0);

  useEffect(() => {
    const id = setInterval(() => {
      setSeconds((s) => s + 1);
    }, 1000);

    return () => clearInterval(id);
  }, []);

  return <p>Elapsed: {seconds} s</p>;
}
Sin clearInterval, el temporizador sobreviviría al componente.

La función devuelta por el efecto es la función de limpieza. React la llama antes de cada nueva ejecución del efecto y, luego, una última vez cuando el componente se desmonta. Es lo que evita las fugas: temporizadores huérfanos, listeners acumulados, suscripciones que nunca se cancelan. Todo efecto que “abre” algo debe volver a cerrarlo.

JSX
useEffect(() => {
  function onResize() {
    setWidth(window.innerWidth);
  }
  window.addEventListener("resize", onResize);

  return () => {
    window.removeEventListener("resize", onResize);
  };
}, []);
Suscripción al evento resize, cancelada al desmontar.

Prueba de conocimientos

Comprueba que has retenido los puntos clave de esta lección.

  1. Con useEffect(fn, []), ¿cuándo se ejecuta la función fn?
    • Antes de cada renderizado del componente
    • Solo después del primer renderizado
    • En cada actualización del estado
  2. ¿Cuándo se llama a la función de limpieza devuelta por un efecto?
    • Solo cuando el componente se desmonta
    • Antes de cada nueva ejecución del efecto y al desmontar
    • Justo antes del primer renderizado del componente
    • Nunca de forma automática: tienes que llamarla tú mismo
  3. Un efecto lee userId pero su array de dependencias es []. ¿Cuál es el problema?
    • El efecto no se volverá a ejecutar cuando userId cambie y conservará un valor obsoleto
    • React lanzará un error en el primer renderizado
    • El efecto se volverá a ejecutar en un bucle infinito