DevPath · Aprenda a programar ESPTEN

Dados e estado global

You Might Not Need an Effect

O abuso do useEffect

useEffect é uma das ferramentas mais usadas em excesso do React. Muita gente o trata como "código que roda quando algo muda", e o enfia por toda parte. Mas um efeito serve para uma coisa concreta: sincronizar seu componente com um sistema externo (a rede, o DOM direto, um setInterval, uma assinatura...). Se você o usa para outra coisa, quase sempre há uma opção melhor, mais simples e sem bugs.

Antipadrão: estado "derivado" como estado + efeito

Caso clássico: você tem nome e sobrenome no estado e quer o nome completo. A tentação é um terceiro estado sincronizado com um efeito:

// ❌ Desnecessário: estado redundante + efeito
function Formulario() {
  const [nome, setNome] = useState("Ada");
  const [sobrenome, setSobrenome] = useState("Lovelace");
  const [completo, setCompleto] = useState("");

  useEffect(() => {
    setCompleto(nome + " " + sobrenome);
  }, [nome, sobrenome]);
  // ...
}

Isto é pior em todos os sentidos: há um estado a mais, um render extra (o efeito roda depois de pintar, e setCompleto provoca outro render) e um momento em que completo fica dessincronizado.

A regra: se você pode calculá-lo a partir de props/estado, faça-o na renderização

O nome completo é estado derivado: não é informação nova, se deriva do que você já tem. Calcule-o durante a renderização, como uma variável normal:

// ✅ Derivado durante a renderização
function Formulario() {
  const [nome, setNome] = useState("Ada");
  const [sobrenome, setSobrenome] = useState("Lovelace");
  const completo = nome + " " + sobrenome; // recalculado a cada render
  // ...
}

Sem efeito, sem estado extra, sem dessincronização. Isto vale para filtrar uma lista, contar elementos, formatar um valor, saber se algo está vazio... tudo isso se calcula na renderização. (Se o cálculo for realmente caro, envolva-o em useMemo para não repeti-lo a cada render; mas useMemo é só uma otimização, não uma mudança de abordagem.)

Antipadrão: lógica de evento dentro de um efeito

Outro mau uso: executar lógica que deveria ir em um manipulador de eventos.

// ❌ Reagir a uma mudança de estado com um efeito para "fazer algo"
useEffect(() => {
  if (enviado) {
    mostrarToast("Compra realizada!");
    esvaziarCarrinho();
  }
}, [enviado]);

Essa lógica acontece porque o usuário clicou em "Comprar", não porque o componente se sincroniza com um sistema externo. Seu lugar é o handler:

// ✅ A lógica da interação vai no manipulador do evento
function comprar() {
  enviarPedido();
  mostrarToast("Compra realizada!");
  esvaziarCarrinho();
}

Regra prática: se algo acontece porque o usuário fez algo (um clique, um submit), vai no manipulador de eventos. Se algo acontece porque o componente apareceu na tela e deve se sincronizar com algo externo, vai em um efeito.

Quando você REALMENTE precisa de um efeito?

Um efeito é a ferramenta correta para sincronizar com sistemas externos ao React:

// ✅ Sincronizar com um sistema externo: com limpeza
useEffect(() => {
  const id = setInterval(() => setSegundos((s) => s + 1), 1000);
  return () => clearInterval(id); // limpeza ao desmontar
}, []);

Antes de escrever um useEffect, pergunte-se: estou sincronizando com algo externo, ou só tento calcular um valor ou responder a uma interação? Nos dois últimos casos, You Might Not Need an Effect.

Coloque isto em prática

O DevPath é um curso prático: aqui você lê a teoria; no app você a coloca em prática com exercícios que rodam de verdade, offline.

Comece grátis no app →
← Estado global: além do ContextVer o módulo →