Front End

6 abr, 2026

7 erros com React moderno que só aparecem em produção; e como evitar

Publicidade

Se você já trabalhou com React em produção, sabe que existe um tipo de bug especialmente traiçoeiro: aquele que simplesmente não aparece no ambiente local. Tudo funciona perfeitamente no desenvolvimento, os testes passam, o deploy vai tranquilo… e, de repente, começam a surgir comportamentos estranhos que ninguém consegue reproduzir com facilidade.

Com o React moderno — especialmente após a introdução de concorrência, Suspense e novas formas de renderização — esses problemas ficaram mais comuns. Isso acontece porque o modelo mental mudou, mas o jeito de programar de muita gente continua o mesmo.

Neste artigo, vamos explorar 7 erros reais que surgem apenas em produção e, mais importante, como evitá-los antes que virem dor de cabeça.

1. Efeitos duplicados e chamadas duplicadas de API

Esse é um clássico que confunde muita gente. Em desenvolvimento, especialmente com Strict Mode ativado, o React executa certos efeitos duas vezes para detectar problemas. Em produção, isso não acontece — o que pode mascarar bugs ou, pior, fazer você “corrigir” algo que não está quebrado.

O problema aparece quando o código não é idempotente e acaba gerando chamadas duplicadas ou estados inconsistentes.

Exemplo problemático

function Users() {
  useEffect(() => {
    fetch('/api/users');
  }, []);

  return <div>...</div>;
}

Dependendo da lógica envolvida (especialmente com side effects externos), você pode ter duplicidade ou inconsistência.

Versão mais segura

function Users() {
  useEffect(() => {
    let isMounted = true;

    async function load() {
      const res = await fetch('/api/users');

      if (isMounted) {
        // atualizar estado com segurança
      }
    }

    load();

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

  return <div>...</div>;
}

Aqui você protege o ciclo de vida e evita efeitos colaterais inesperados.

2. Race conditions em requisições concorrentes

Com concorrência, o React pode disparar múltiplas atualizações, e isso abre espaço para um problema clássico: respostas chegando fora de ordem.

Exemplo real

function Search() {
  const [query, setQuery] = useState('');
  const [results, setResults] = useState([]);

  useEffect(() => {
    fetch(`/api/search?q=${query}`)
      .then(res => res.json())
      .then(setResults);
  }, [query]);

  return <input onChange={e => setQuery(e.target.value)} />;
}

Se o usuário digitar rápido:

  • requisição A (lenta)
  • requisição B (rápida)

👉 A pode sobrescrever B

Solução com cancelamento

function Search() {
  const [query, setQuery] = useState('');
  const [results, setResults] = useState([]);

  useEffect(() => {
    const controller = new AbortController();

    async function fetchData() {
      const res = await fetch(`/api/search?q=${query}`, {
        signal: controller.signal,
      });

      const data = await res.json();
      setResults(data);
    }

    fetchData();

    return () => controller.abort();
  }, [query]);

  return <input onChange={e => setQuery(e.target.value)} />;
}

Agora você evita sobrescrita indevida.

3. Uso incorreto de Suspense causando telas travadas

Suspense é poderoso, mas mal utilizado pode travar a interface inteira, especialmente quando você envolve blocos grandes demais sem granularidade.

Exemplo problemático

<Suspense fallback={<p>Carregando...</p>}>
  <Dashboard />
</Suspense>

Se o Dashboard for pesado:

👉 a tela inteira fica bloqueada

Abordagem mais granular

<Suspense fallback={<p>Carregando perfil...</p>}>
  <UserProfile />
</Suspense>

<Suspense fallback={<p>Carregando posts...</p>}>
  <UserPosts />
</Suspense>

Agora o carregamento é progressivo e mais fluido.

4. Hidratação inconsistente em SSR

Se você usa Next.js ou qualquer SSR, esse erro é comum.

O HTML gerado no servidor precisa bater com o que o cliente renderiza.

Se não bater:

👉 erro de hidratação
👉 comportamento imprevisível

Exemplo problemático

export default function Page() {
  const random = Math.random();

  return <p>{random}</p>;
}

Servidor e cliente vão gerar valores diferentes.

Solução

export default function Page() {
  const [random, setRandom] = useState<number | null>(null);

  useEffect(() => {
    setRandom(Math.random());
  }, []);

  return <p>{random}</p>;
}

Agora o valor só existe no client.

5. Re-renderizações em cascata (performance invisível)

Esse tipo de problema não quebra funcionalidade, mas destrói performance em produção.

Exemplo

function Parent() {
  const [count, setCount] = useState(0);

  return <Child onClick={() => setCount(count + 1)} />;
}

Cada render cria uma nova função.

👉 Child re-renderiza sempre

Correção

const handleClick = useCallback(() => {
  setCount(c => c + 1);
}, []);

return <Child onClick={handleClick} />;

6. Estado desatualizado (stale closures)

Esse bug é clássico e difícil de perceber.

Exemplo problemático

function Counter() {
  const [count, setCount] = useState(0);

  function incrementLater() {
    setTimeout(() => {
      setCount(count + 1);
    }, 1000);
  }

  return <button onClick={incrementLater}>{count}</button>;
}

Se clicar várias vezes:

👉 valor pode ficar inconsistente

Correção

setCount(c => c + 1);

Agora sempre usa o estado mais recente.

7. Dependências erradas no useEffect

Esse é silencioso e perigoso.

Exemplo

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

Se userId mudar:

👉 efeito não roda novamente

Correção

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

O padrão invisível por trás de todos esses erros

Se você observar bem, todos esses problemas têm algo em comum:

👉 assumem comportamento síncrono
👉 ignoram concorrência
👉 ignoram ciclo real de render

O modelo mental correto

React moderno não garante:

  • ordem de execução
  • número de renders
  • sincronização simples

Ele garante:

👉 consistência final da UI

Conclusão: produção expõe o que o dev esconde

Ambiente local é controlado. Produção não é.

É em produção que aparecem latência real, concorrência real e uso real. E é aí que decisões aparentemente pequenas viram problemas grandes.