JavaScript/React/useEffect
JavaScript⏱ ~2 min de leitura

useEffect

Efeitos colaterais e ciclo de vida

useEffect é o hook para sincronizar um componente com sistemas externos: APIs, localStorage, WebSocket, timers, assinaturas. Ele roda depois que o componente renderizou no DOM e recebe uma função de efeito e um array de dependências.

O array de dependências controla quando o efeito roda: array vazio [] → roda apenas no mount (montagem); com valores [a, b] → roda no mount e toda vez que a ou b mudar; sem array → roda após cada re-render (raramente o que você quer). A função pode retornar outra função de cleanup que o React chama antes do próximo efeito ou ao desmontar o componente.

Erros comuns: esquecer dependências (o efeito usa uma variável mas não a lista — acessa valor desatualizado), criar loops infinitos (o efeito muda um estado que está nas dependências), e não limpar assinaturas/timers (vazamentos de memória).

Exemplo.java
import { useState, useEffect } from "react";

// ── Buscar dados de uma API ───────────────────────
function Usuarios() {
  const [usuarios, setUsuarios] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    let cancelado = false; // evita atualização após unmount

    async function buscar() {
      try {
        const res = await fetch("https://jsonplaceholder.typicode.com/users");
        const data = await res.json();
        if (!cancelado) setUsuarios(data);
      } finally {
        if (!cancelado) setLoading(false);
      }
    }

    buscar();
    return () => { cancelado = true; }; // cleanup
  }, []); // [] = roda só no mount

  if (loading) return <p>Carregando...</p>;
  return <ul>{usuarios.map(u => <li key={u.id}>{u.name}</li>)}</ul>;
}

// ── Sincronizar com localStorage ──────────────────
function Tema() {
  const [tema, setTema] = useState(
    () => localStorage.getItem("tema") ?? "dark" // inicialização lazy
  );

  useEffect(() => {
    localStorage.setItem("tema", tema);
    document.documentElement.dataset.tema = tema;
  }, [tema]); // roda toda vez que tema mudar

  return <button onClick={() => setTema(t => t === "dark" ? "light" : "dark")}>
    {tema}
  </button>;
}

// ── Timer com cleanup ─────────────────────────────
function Relogio() {
  const [tempo, setTempo] = useState(new Date());

  useEffect(() => {
    const id = setInterval(() => setTempo(new Date()), 1000);
    return () => clearInterval(id); // ← cleanup essencial!
  }, []);

  return <p>{tempo.toLocaleTimeString()}</p>;
}
💡 Dica pro

Se o efeito busca dados, crie uma variável de cancelamento ou use AbortController para evitar atualizar o estado de um componente desmontado. React 18 strict mode monta/desmonta componentes duas vezes em dev para detectar esses problemas.

Recompensa+40 XP+exercícios