Quando a gente começa com React, é muito tentador só ir criando arquivos e pastas até “funcionar”. O problema é que, depois de alguns meses, ninguém mais sabe onde está a regra de negócio, onde está só UI e o que pode ou não ser reutilizado.
É aí que uma arquitetura minimamente pensada começa a fazer diferença de verdade. Ganho de previsibilidade, menos gambiarra e bem menos medo de mexer em código antigo.
Basicamente é assim
No dia a dia, uma estrutura bem comum é ter algo como:
components/, pages/ (ou screens/), services/, utils/, contexts/ ou stores/, hooks/ e,
dependendo da maturidade do projeto, até:
models/, controllers/ e repositories/.
components/é onde ficam as peças reutilizáveis de UI: botão, input, modal, layout, card, essas coisas que não deveriam saber muito sobre regra de negócio.
pages/normalmente representa as telas/rotas, tipo Login, Dashboard, ProductList, e é ali que você junta componentes, chama serviços e conecta os dados.
services/ centraliza chamadas HTTP e integrações externas, enquanto utils/ guarda as funções genéricas que você acaba usando em vários lugares, como formatar datas, validar campos ou transformar dados.
Se você quiser trazer um pouco da ideia de MVC (Model View Controller) para o frontend,
dá para pensar dessa forma aqui:
- “View” são seus componentes e páginas,
- “Model” aparece nos tipos e interfaces TypeScript (às vezes em uma pasta models/),
- “Controller” fica espalhado em hooks, containers ou em uma pasta controllers/ quando você decide formalizar isso.
Em projetos maiores, faz bastante sentido criar controllers e repositoriesseparados, um UserRepository, por exemplo, concentra tudo que fala com a API de usuário, enquanto um UserController(ou um useUserController) orquestra fluxo, lida com loading, erros, estado local e dispara ações na store.
*Essa divisão deixa claro quem conversa com a API, quem aplica regra de negócio e quem só renderiza a tela.
*
Chega uma hora em que useState em tudo e props para todo lado deixam de funcionar bem, especialmente em telas mais complexas.
Nesse ponto entram Context API, Redux, MobX, Zustand, etc., geralmente organizados em
contexts/ oustores/.
*Você pode ter, por exemplo, AuthContext, ThemeContext, CartStore, cada um cuidando de um pedaço bem definido do estado global. *
A graça aqui é separar o “cérebro” da aplicação da parte visual. Componentes não precisam saber como o estado é gerenciado, só consomem o que precisam e disparam ações quando algo acontece.
Em empresas onde já trabalhei com React **e **TypeScript, incluindo a Codetech Software, essa separação por domínio (auth, pagamentos, catálogo, etc.) dentro de contexts/stores fez muita diferença na hora de escalar o time e o código.
Quando você traz Next.js para a conversa, a coisa muda um pouco,
mas os princípios continuam os mesmos. O framework já te dá uma estrutura de rotas (app/ ou pages/) e, com a App Router mais recente, ainda entra a divisão entre server components e client components. Por padrão, páginas e layouts são server components, e você marca como client quando precisa de estado, hooks, eventos de clique e acesso ao window.
Na prática, muita gente acaba separando visualmente esses dois mundos, seja por nome de arquivo (.client.tsx) ou por pastas, para ficar claro o que roda no servidor e o que realmente precisa ir para o browser.
Dá também para misturar isso tudo com Atomic Design (deixei o link de uma documentação do Atomic design pra dar um contexto) (atoms, molecules, organisms, templates, pages), organizando seus componentes por nível de granularidade e não só por tipo de arquivo ou rota. Mas aí já é conversa para outro artigo.
O que mais importa aqui é ter clareza de responsabilidades:
componentsfocados em UI, pages orquestrando a tela,
servicesfazendo I/O,
utilsresolvendo o “trabalho sujo” genérico,
contexts/stores segurando o estado global e, se fizer sentido para o seu time,
controllers e repositories organizando a lógica de negócio em camadas.
Em projetos React com TypeScript que mexi, quando essa arquitetura está minimamente alinhada, o código flui melhor, o onboarding de dev novo dói menos e refatorar deixa de ser um terror para virar parte natural da evolução do produto.



Top comments (0)