rochasolutions
Arquitetura

Gerenciamento de Estado em React: Qual Abordagem Escolher?

Danilo Rocha5 min de leitura

O que é gerenciamento de estado em React

Gerenciamento de estado é a forma como uma aplicação guarda, atualiza e distribui os dados que mudam ao longo do tempo: o que o usuário digitou, se um modal está aberto, a lista que veio da API. Em React, cada abordagem de gerenciamento de estado resolve um problema diferente, e usar a errada custa em complexidade ou em performance.

O erro mais comum é usar a abordagem errada para o tamanho do problema: aplicar uma solução global a um caso local, forçar uma biblioteca pesada onde dois useState resolveriam, ou sustentar o estado de um sistema inteiro em Context API e sofrer com re-render em cascata.

Este artigo cobre quando cada abordagem de gerenciamento de estado em React faz sentido e como decidir sem depender de modismo.

Quando o useState resolve e quando ele começa a doer

useState resolve bem estado local: um campo de formulário, um contador, um accordion aberto, um toggle de tema escuro. Ele começa a doer quando o mesmo dado precisa aparecer em componentes que não têm relação direta de pai e filho.

O sintoma é sempre o mesmo: prop drilling. Um dado sobe até um ancestral comum e desce de novo por três, quatro, cinco níveis de componentes que não usam esse dado, só repassam. Cada componente no meio vira acoplamento desnecessário: mudar a assinatura de uma prop no topo obriga a mexer em todo o caminho até o consumidor final.

function Pagina() {
  const [usuario, setUsuario] = useState(null);
  return <Layout usuario={usuario} />;
}

function Layout({ usuario }) {
  return <Sidebar usuario={usuario} />;
}

function Sidebar({ usuario }) {
  return <Avatar usuario={usuario} />;
}

Layout e Sidebar não usam usuario para nada além de repassar adiante. Esse é o ponto em que vale considerar outra abordagem, não antes disso.

Context API resolve prop drilling, não substitui um gerenciador global

Context API é um mecanismo do React para passar dado através da árvore de componentes sem repassar prop manualmente em cada nível. Ele resolve prop drilling, mas não foi desenhado para estado que muda com frequência alta.

O problema de performance é direto: todo componente que consome um Context re-renderiza quando o valor do Context muda, mesmo que use só uma fatia pequena daquele valor. Um Context com { usuario, tema, carrinho, notificacoes } faz o componente que só lê tema re-renderizar toda vez que o carrinho muda.

A prática que evita isso é separar Contexts por domínio, um para cada fatia de estado que muda em ritmo diferente, em vez de manter um Context único para a aplicação inteira. Ainda assim, para estado que atualiza a cada tecla digitada ou a cada scroll, Context tende a custar caro demais em re-renders.

Quando trocar Context por Zustand, Jotai ou Redux

Bibliotecas externas de gerenciamento de estado resolvem o problema de re-render do Context: o componente só re-renderiza quando o pedaço específico de estado que ele lê muda, não quando qualquer parte do estado muda.

Zustand e Jotai compartilham essa filosofia de assinatura seletiva, com sintaxe mais enxuta que Redux. Zustand usa um hook único por store, sem Provider obrigatório:

import { create } from 'zustand';

const useCarrinho = create((set) => ({
  itens: [],
  adicionar: (item) => set((state) => ({ itens: [...state.itens, item] })),
}));

Redux continua fazendo sentido em times grandes que já têm a estrutura montada em volta dele: Redux DevTools para depurar cada ação disparada, middleware para lidar com efeito colateral, um padrão único que todo desenvolvedor do time já conhece de outros projetos. Para um projeto novo sem esse histórico de time, a complexidade extra do Redux raramente se paga.

Como decidir a abordagem certa para o seu projeto

Siga esta ordem antes de adicionar qualquer biblioteca de gerenciamento de estado ao projeto:

  1. Pergunte se o estado é usado por um componente só. Se sim, useState ou useReducer resolvem e nada além disso é necessário.
  2. Pergunte se o estado é compartilhado, mas muda pouco: tema, idioma, dados do usuário logado. Context API resolve sem custo relevante de performance.
  3. Meça o re-render antes de trocar de abordagem. O React DevTools Profiler mostra quais componentes re-renderizam e por quê. Sem esse dado, trocar de Context para Zustand é chute.
  4. Se o Profiler confirmar re-render em cascata em estado que muda com frequência, migre a fatia específica de estado, não o projeto inteiro, para Zustand ou Jotai.
  5. Considere Redux só se o time já tem esse padrão consolidado em outros projetos, ou se o app precisa de rastreamento de ação para auditoria.

Pular a etapa de medir é o erro mais caro de todos. Trocar de biblioteca sem confirmar que o gargalo é gerenciamento de estado, quando o problema real está em outro lugar, como uma imagem sem otimização (veja como otimizar o LCP do site), custa tempo de reescrita sem resolver o sintoma original.

Erros comuns que pioram a performance do estado em React

O erro mais frequente é colocar estado que muda a cada tecla, como o valor de um input de busca, direto num Context ou numa store global. Isso propaga re-render para todo consumidor a cada caractere digitado, mesmo quando só o próprio input precisa daquele valor.

Outro erro é normalizar estado demais cedo. Duplicar um dado da API em três stores diferentes, para garantir acesso fácil de qualquer componente, cria divergência: a store A atualiza e a store B fica com o valor antigo, e ninguém lembra qual é a fonte de verdade.

Memoização mal aplicada também esconde o problema em vez de resolver. Envolver tudo em useMemo e useCallback sem medir onde o re-render realmente incomoda adiciona complexidade sem ganho, porque comparar dependências a cada renderização também tem custo.

Se seu projeto React já mostra sinais de re-render em cascata ou o time perde tempo depurando qual store tem a verdade sobre um dado, fale com a gente para uma revisão de arquitetura.