Pular para o conteúdo principal

`useEffect` não é sua primeira opção. É seu último recurso.

Todo dev React aprende useEffect cedo. E passa anos usando errado.

Não é culpa sua. O nome parece genérico o suficiente para encaixar em qualquer coisa. Mas a API tem um contrato específico: sincronizar com o mundo externo ao React. DOM, network, browser API.

Se você não está cruzando essa fronteira, você provavelmente não precisa de efeito.


Estado derivado não precisa de efeito

O erro mais comum. Um valor depende de outro estado, então você os sincroniza:

// Don't do thisconst [items, setItems] = useState([]);const [count, setCount] = useState(0); useEffect(() => {  setCount(items.length);}, [items]);

Duas renderizações para algo que você pode calcular diretamente. React renderiza com count desatualizado, o efeito roda, atualiza, React renderiza de novo.

Simplesmente calcule:

// Do this insteadconst [items, setItems] = useState([]);const count = items.length;

Sem estado. Sem efeito. Sem render extra.


Filtrar dados não precisa de efeito

Mesmo erro, formato diferente:

// Don't do thisconst [query, setQuery] = useState("");const [filtered, setFiltered] = useState(todos); useEffect(() => {  setFiltered(todos.filter((t) => t.text.includes(query)));}, [todos, query]);

Duas renderizações por mudança. Calcule inline:

// Do this insteadconst [query, setQuery] = useState("");const filtered = todos.filter((t) => t.text.includes(query));

Se o cálculo for pesado, use useMemo. Ele faz cache do resultado, não agenda atualização de estado como useEffect + setState:

const filtered = useMemo(  () => todos.filter((t) => t.text.includes(query)),  [todos, query]);

Responder a eventos não precisa de efeito

Usuário fez algo? Responda no handler:

// Don't do thisconst [submitted, setSubmitted] = useState(false); useEffect(() => {  if (submitted) {    sendAnalytics("form_submit");    setSubmitted(false);  }}, [submitted]); function handleSubmit() {  setSubmitted(true);}

Isso é uma forma indireta de dizer "quando o usuário enviar, dispare o analytics". Coloque direto no handler:

// Do this insteadfunction handleSubmit() {  sendAnalytics("form_submit");}

A regra é simples: ação do usuário -> handler. Componente apareceu na tela e precisa sincronizar com algo externo -> efeito.


Resetar estado ao mudar prop não precisa de efeito

// Don't do thisfunction ProfilePage({ userId }) {  const [comment, setComment] = useState("");   useEffect(() => {    setComment("");  }, [userId]);   // ...}

Renderiza com estado desatualizado primeiro, depois o efeito limpa. Use key:

// Do this instead// In the parent:<ProfilePage userId={id} key={id} />

key diferente = nova instância. Estado começa limpo, sem código extra.


Quando useEffect é a resposta certa

  • Event listeners (resize, scroll, WebSockets)
  • Integrações com bibliotecas que manipulam o DOM diretamente
  • Fetch de dados, mas prefira SWR ou TanStack Query, eles resolvem race conditions que você vai ignorar
// This is a valid use of useEffectuseEffect(() => {  const handler = () => setWindowWidth(window.innerWidth);  window.addEventListener("resize", handler);  return () => window.removeEventListener("resize", handler);}, []);

A pergunta que resolve tudo

Antes de escrever useEffect:

Estou sincronizando com algo fora do React?

  • Calculando um valor a partir de estado ou props? Calcule durante o render.
  • Cálculo pesado? Use useMemo.
  • Respondendo a ação do usuário? Use um handler.
  • Precisa resetar estado quando prop muda? Use key.

useEffect é válvula de escape. Não é padrão.

Voltar