useEffect se dispara de forma inesperada y afecta al rendimiento de tu aplicación.

El truco

Antes (mal)

useEffect(() => {
  fetchData();
}, [dependency1, dependency2]);

Después (bien)

useEffect(() => {
  let isMounted = true;
  
  fetchData().then(() => {
    if (isMounted) {
      // Actualiza el estado solo si el componente sigue montado
    }
  });

  return () => {
    isMounted = false;
  };
}, [dependency1, dependency2]);

useEffect no siempre se cancela automáticamente si el componente se desmonta antes de que una promesa termine. Añadir un flag de isMounted evita que intentemos actualizar el estado de un componente desmontado, previniendo errores de memoria y ejecuciones no deseadas.

useEffect invoca funciones incesariamente con dependencias que no cambian.

El truco

Antes (mal)

useEffect(() => {
  expensiveCalculation();
}, [dependency1, dependency2, dependency3]);

Después (bien)

useMemo(() => expensiveCalculation(), [dependency1, dependency3]);

useEffect(() => {
  // Usa aquí el resultado de useMemo si es necesario
}, [dependency2]);

Separar cálculos intensivos en funciones memoizadas con useMemo reduce las llamadas ineficientes dentro de useEffect, haciéndolo más rápido y eficiente.

useEffect se comporta de forma errática debido a dependencias incompletas.

El truco

Antes (mal)

useEffect(() => {
  doSomething(data);
}, []);

Después (bien)

useEffect(() => {
  doSomething(data);
}, [data]);

Dejar las dependencias vacías cuando usas data dentro del efecto implica que cualquier cambio en data no actualiza el efecto. Es fundamental incluir todas las dependencias necesarias para asegurar que el efecto se comporta como se espera.

Limpia tu código y optimiza la eficiencia de tus componentes React vigilando cómo usas useEffect.