Arquitetura React: Como Estruturar um Projeto que Escala
O que é arquitetura React
Arquitetura React é o conjunto de decisões sobre como o código de uma aplicação se organiza: onde cada arquivo mora, como as camadas se comunicam e quais regras determinam se algo é componente, hook ou serviço. Nenhum framework ou biblioteca impõe essa divisão sozinho. Ela é o resultado de escolhas do time sobre como separar lógica de negócio, dados e interface.
Um projeto React sem arquitetura definida costuma funcionar bem nos primeiros meses.
O problema aparece depois, quando o time cresce, o número de telas passa de vinte e
cada novo desenvolvedor demora dias só para entender onde adicionar uma função. Nesse
ponto, a pasta components já tem duzentos arquivos sem nenhuma hierarquia, e ninguém
sabe mais qual componente depende de qual.
Organização por feature ou por tipo de arquivo
Organizar por feature agrupa tudo que uma funcionalidade usa, componente, hook,
serviço e teste, dentro de uma única pasta. Organizar por tipo de arquivo separa por
categoria técnica: uma pasta components, outra hooks, outra services, cada uma
com arquivos de features diferentes misturados.
A organização por tipo parece limpa no início, porque segue uma convenção visual
simples. O custo aparece quando alguém precisa mexer na feature de checkout: o
componente está em components, o hook que busca o carrinho está em hooks, a
chamada de API está em services, e o teste está numa quarta pasta. Editar uma
funcionalidade vira um exercício de abrir cinco pastas diferentes para lembrar onde
cada parte ficou.
A organização por feature resolve isso agrupando por proximidade de uso, não por categoria técnica:
src/
features/
checkout/
Checkout.tsx
useCarrinho.ts
checkoutService.ts
Checkout.test.tsx
perfil/
Perfil.tsx
usePerfil.ts
perfilService.ts
components/
Button.tsx
Card.tsx
A pasta components na raiz sobra só para o que é genérico de verdade: botão, card,
input, qualquer coisa reutilizada por mais de uma feature. Tudo que pertence a uma
única funcionalidade fica dentro dela. Quando a feature de checkout for descontinuada,
a pasta inteira sai junto, sem deixar arquivo órfão espalhado pelo projeto.
Camadas: separando lógica, dados e apresentação
Uma camada de apresentação, uma de estado e uma de acesso a dados evitam que a lógica de negócio fique presa dentro do componente visual. Isso é o que permite testar a regra sem precisar renderizar tela, e trocar a fonte de dados sem tocar no JSX.
Na prática, isso significa três tipos de arquivo dentro de cada feature. O componente cuida só de renderizar o que recebe e disparar eventos. O hook customizado guarda o estado e a lógica que decide o que mostrar, como validação de formulário ou regra de negócio. O serviço isola a chamada HTTP ou de banco, sem saber nada sobre React.
Esse tipo de separação é o motivo pelo qual gerenciamento de estado em
React importa tanto quanto a arquitetura de
pastas: um hook de estado bem isolado pode trocar de useState para uma biblioteca
externa sem que nenhum componente precise mudar uma linha.
O sinal de que a separação está funcionando é simples: dá para ler o componente e entender o que a tela mostra, sem precisar saber de onde vem o dado. E dá para ler o serviço sem precisar saber em qual tela ele é usado.
Como estruturar um projeto React do zero
Definir a arquitetura antes de escrever a primeira tela evita boa parte da reorganização que costuma aparecer depois de seis meses de projeto.
- Defina a pasta raiz de features antes de criar qualquer componente. Toda
funcionalidade nova nasce dentro dela, nunca solta em
components. - Separe o que é genérico do que é específico. Um componente só vai para a pasta compartilhada quando pelo menos duas features diferentes precisarem dele.
- Escreva o serviço de dados sem importar nada do React. Se o serviço importa
useStateouuseEffect, a camada está misturada. - Coloque o teste ao lado do arquivo que ele testa, dentro da mesma pasta de feature, para que mudar a funcionalidade e mudar o teste seja um único gesto.
- Documente, num arquivo curto na raiz do projeto, a regra de onde cada tipo de arquivo mora. Isso evita que cada desenvolvedor novo invente a própria convenção.
- Revise a estrutura a cada trimestre. Uma feature que cresceu demais pode precisar virar duas, e isso só fica claro olhando o projeto de fora, não durante a correria de uma sprint.
Erros comuns de arquitetura React em projetos que crescem
O erro mais frequente é a pasta utils que vira depósito de tudo que não tem lugar
óbvio. Com o tempo, ela acumula funções sem relação nenhuma entre si, e ninguém sabe
mais buscar ali primeiro. Se uma função só serve a uma feature, ela deveria morar
dentro da pasta dessa feature, não num arquivo genérico de utilidades.
Outro erro é criar abstração cedo demais. Um contexto global, uma camada de injeção de dependência ou um padrão de design elaborado fazem sentido quando o problema que resolvem já apareceu duas ou três vezes no projeto. Antes disso, a abstração custa mais tempo de manutenção do que resolve, porque ninguém sabe ainda qual é a forma certa do problema.
O terceiro é deixar a chamada de API dentro do componente, direto no useEffect. Isso
parece mais rápido de escrever no primeiro momento, mas amarra a tela à origem do
dado. Se depois o mesmo dado precisar vir de outro endpoint, ou for reaproveitado em
outra tela, a lógica precisa ser copiada em vez de reutilizada.
Uma arquitetura React boa garante que qualquer pessoa do time, inclusive uma que entrou ontem, consiga prever onde um arquivo mora só olhando o nome da feature. A estrutura de pastas específica importa menos do que essa previsibilidade. Se o seu projeto já passou do ponto em que isso é verdade, fale com a gente para revisar a arquitetura antes que a reorganização fique mais cara do que é hoje.