¿Tu useEffect corre demasiado o no lo suficiente? Es por la mala gestión de dependencias.

El truco

// ANTES (Mal)
useEffect(() => {
  fetchData();
});

// DESPUÉS (Bien)
useEffect(() => {
  fetchData();
}, [fetchData]);

Sin lista de dependencias, useEffect se ejecuta en cada render. Añadir dependencias específicas limita las ejecuciones.

Te encuentras con un efecto infinito por dependencias que cambian constantemente.

El truco

// ANTES (Mal)
useEffect(() => {
  setCount(count + 1);
}, [count]);

// DESPUÉS (Bien)
useEffect(() => {
  setCount(prevCount => prevCount + 1);
}, []);

Al usar el estado directamente, puedes entrar en un bucle infinito. Usar funciones actualizadoras evita este error.

Olvidas limpiar el efecto, y los recursos se quedan colgados.

El truco

// ANTES (Mal)
useEffect(() => {
  const id = setInterval(doSomething, 1000);
}, []);

// DESPUÉS (Bien)
useEffect(() => {
  const id = setInterval(doSomething, 1000);
  return () => clearInterval(id);
}, []);

Siempre limpia los efectos que asignan recursos, como setInterval, para evitar fugas de memoria.

Estás duplicando lógica de la función useEffect.

El truco

// ANTES (Mal)
useEffect(() => {
  if (!data) {
    fetchData().then(setData);
  }
}, [data]);

// DESPUÉS (Bien)
useEffect(() => {
  fetchData().then(setData);
}, []);

No verifiques dentro del useEffect algo que se puede manejar directamente desde el efecto, evitando lógica redundante.

Dependes de variables que no están en la lista de dependencias.

El truco

// ANTES (Mal)
useEffect(() => {
  doSomething();
}, []);

// DESPUÉS (Bien)
useEffect(() => {
  doSomething();
}, [dependency]);

Incluye todas las dependencias necesarias para asegurarte de que useEffect responde correctamente a sus cambios.

Usar useEffect correctamente garantiza que tu aplicación funcione sin problemas y te ahorra muchos dolores de cabeza.