React: os cinco padrões de componente e o lugar de cada estado
Quem encomenda telas a um agente de IA recebe React em quantidade e precisa saber revisar o que chega. Este guia reúne o que o curso ensina para essa revisão: no React o estado é a única fonte de verdade sobre como a tela se mostra, e alterar o DOM na mão é o atalho proibido; cinco padrões de componente cobrem a maioria das telas, cada um com o seu sinal de reprovação; antes de criar qualquer estado, a pergunta que custa trinta segundos é onde mora a verdade daquele dado; dado de servidor vive numa camada de cache; formulário com três campos ou mais pede biblioteca que evite o redesenho a cada tecla; filtro, aba e busca moram na URL; e no Next.js a fronteira entre servidor e navegador se decide componente a componente.
Guia derivado dos capítulos de React, Tailwind e CSS, de formulários, do benchmark de stacks e de tabelas do curso Frontends com Vibecoding, de Alexandre Caramaschi, com as datas e atribuições que o curso registra. Ele compõe o menu Design com os guias de ícones, ilustrações, animação e geração de imagens e de menus, abas e paginação.
O princípio que organiza tudo
A frase que abre o apêndice do curso resume o problema de quem revisa código de agente: "o agente escreve muito bem o React, o Tailwind e o CSS de dois anos atrás. Ele acerta a estrutura, erra a atualidade, e nada no processo avisa." A revisão existe para cobrir esse vão, e ela parte de um princípio único: no React o estado é a única fonte de verdade sobre como a tela se mostra. O fluxo correto é sempre o mesmo: a interação atualiza o estado, o React re-renderiza, a classe do Tailwind muda e a tela muda. O desvio vermelho é alterar o DOM na mão — quando isso aparece num componente, o resto da revisão pode esperar, porque a fonte de verdade já foi traída.
A armadilha das classes montadas. O Tailwind só gera as classes que consegue ver como strings completas no código-fonte. Por isso bg-${cor}-500 ou 'text-' + tom produzem classe nenhuma no arquivo final. A solução ensinada é o mapa estático de variantes: um objeto com as strings inteiras (variantes[variante]), que o Tailwind enxerga e o revisor confere de relance.
Os cinco padrões de componente e o sinal de reprovação de cada um
O curso reduz a maioria das telas a cinco padrões. Revisar vira reconhecer qual padrão está diante de você e procurar o sinal que reprova aquele padrão específico:
1. Componente com props
Função tipada que devolve JSX; a prop decide a classe aplicada (uma prop destaque escolhe a aparência do bloco). Reprove quando a lista de props passou de meia dúzia e cresce a cada tela.
2. Composição por children
Invólucro genérico que cuida só de enquadramento, borda, fundo e espaçamento. É o padrão mais reutilizável do React justamente porque o invólucro dispensa saber qualquer coisa sobre o que carrega. Reprove quando o invólucro recebe props do que ele carrega.
3. Estado local com useState
Regra de ouro: atualize sempre a partir do valor anterior, na forma (v) => v + 1, para que duas atualizações próximas deixem de se atropelar. Cada booleano recebe nome que descreve a condição, e o nome pela aparência é vício. Reprove quando o DOM é alterado na mão em vez de reconciliado.
4. Lista com map e key
A key vem do identificador do dado. O índice muda quando a ordem muda e o React passa a reaproveitar o elemento errado. Trate sempre o caso de lista vazia. Reprove quando a key é o índice do array ou o caso vazio ficou sem tratamento.
5. Campo controlado
O value vem do estado e o onChange atualiza; o erro reflete na borda vermelha e no aria-invalid ao mesmo tempo. Reprove quando o erro aparece só em cor, ou só depois do envio.
O fluxo de leitura para revisar um componente devolvido, na ordem do curso: que padrão é este? Ele cabe na situação? O critério aparece no código? Algum sinal de reprovação? Então aprovar, ou devolver com o motivo em uma frase.
O exemplo canônico do capítulo é um Button.tsx com props tipadas (label, variant, onClick, disabled), o mapa estático de variantes comentado no próprio código ("Variantes como mapa estático — Tailwind precisa ver") e as classes de estado acessível compostas na string: focus-visible:ring-2, disabled:opacity-50, disabled:cursor-not-allowed. Os demais exemplos descritos: interruptor com role="switch" e aria-checked movendo a bolinha via translate-x; abas com borda inferior somando cor e posição para indicar a seleção; cartão de indicador que deriva seta e cor do sinal da variação numérica; e cartão de usuário com fallback de iniciais e esqueleto motion-safe:animate-pulse.
Onde mora cada estado: a pergunta de trinta segundos
Antes de criar qualquer estado, responda uma coisa: onde mora a verdade deste dado. O curso trata a confusão entre os tipos de estado como a causa raiz da maioria dos bugs de estado — o sintoma clássico é uma tela mostrando um saldo e a outra mostrando outro — e avisa que errar a classificação transforma a correção: ela deixa de ser ajuste de tela e vira reescrita da camada de dados. Os tipos:
- Local — pertence a um componente só (aba ativa, campo aberto); mora em
useStateouuseReducer. - Derivado — calculável de outros valores (total, lista filtrada); calcule, nunca guarde: guardar cria duas fontes de verdade que divergem na primeira alteração.
- Compartilhado de cliente — atravessa telas sem vir do servidor (tema, sessão, carrinho); Context para baixa frequência, Zustand ou Jotai para alta frequência e estado granular.
- De servidor — pertence ao backend (lista de pedidos); mora em camada de cache: TanStack Query ou Server Component.
- O quinto lugar, esquecido — o endereço da tela: filtro, aba, ordenação e página moram na URL, via nuqs.
| Tipo de estado | Exemplo | Ferramenta | Evite |
|---|---|---|---|
| Local | Aba de um cartão, campo aberto | useState ou useReducer | Biblioteca global |
| Derivado | Total, lista filtrada | Calcular na renderização; useMemo só se caro | Guardar em useState |
| Compartilhado, baixa frequência | Tema, sessão, modal global | Context com useReducer | Store pesado |
| Compartilhado, alta frequência | Carrinho, estado de funcionalidade | Zustand, com seletores e useShallow | Context, que re-renderiza em cascata |
| Compartilhado, granular | Formulário ou editor complexo | Jotai, por átomos | Um store monolítico |
| Filtro, aba, paginação, busca | ?busca=...&página=2 | nuqs, estado na URL | useState que some no recarregamento |
| De servidor | Lista de produtos, perfil | TanStack Query ou Server Component | useState com useEffect |
| Fonte externa | Tamanho da janela, store próprio | useSyncExternalStore | useEffect improvisado |
Quadro "Qual ferramenta para qual estado" do curso Frontends com Vibecoding.
Estado compartilhado: o custo de re-render de cada ferramenta
A diferença entre as três ferramentas de estado compartilhado é quem redesenha quando o valor muda. Com Context e useReducer, todo consumidor re-renderiza quando o value do Provider muda, mesmo lendo uma fatia que permaneceu igual — bom para valor estável e raro, caro em alta frequência. Com Zustand, cada componente assina só a fatia que usa via seletor, sem Provider e sem re-render em cascata; a armadilha citada é selecionar vários valores retornando objeto ou array novo, o que exige useShallow sob pena do erro de profundidade máxima de atualização. Com Jotai, átomos primitivos se compõem e o re-render fica restrito a quem lê o átomo alterado — rende mais em estado granular e derivado, o caso do formulário complexo e do editor.
Três saídas antes de migrar do Context, na ordem do curso: quebrar um Context grande em vários pequenos por frequência de mudança; estabilizar o value com useMemo; e, se a alta frequência persistir, trocar por store com seletores.
Para os casos em que a atualização disputa com a digitação, o curso apresenta as primitivas de concorrência: useTransition marca uma atualização como baixa prioridade e expõe o sinal de pendência; useDeferredValue deixa o valor digitado chegar na hora e adia a versão derivada; e useSyncExternalStore é o hook oficial para conectar o React a uma fonte externa, como o tamanho da janela, o status de rede ou um store escrito à mão — você raramente o escreve direto, e saber que ele existe explica por que bibliotecas como o Zustand funcionam com segurança no render concorrente.
Um caso à parte vem do capítulo de tabelas: dado que muda várias vezes por segundo fica fora do ciclo de renderização — o jeito certo mantém os dados quentes dentro do motor e repinta apenas o que mudou. O teste que expõe o defeito leva um minuto: abra o painel de componentes do React e observe se o componente pai redesenha a cada atualização. Se redesenhar, o dado está no lugar errado.
Dado de servidor: cache, e nunca useState com useEffect
Buscar dados com a dupla useState mais useEffect e guardá-los num store global reimplementa, à mão e mal, uma camada de cache — sem revalidação, sem deduplicação e sem estado de obsolescência. A ferramenta do curso para esse trabalho é o TanStack Query: cache, deduplicação de chamadas, revalidação ao voltar à aba e estados prontos, com useQuery para leitura (data, isPending, isError, refetch), useMutation para escrita, invalidação por chave, retry automático e paginação com rolagem infinita. O curso registra a linha 5 como a atual em julho de 2026, segundo a documentação do próprio projeto.
O passo a passo da ficha: instalar @tanstack/react-query; criar o QueryClient e envolver a aplicação em QueryClientProvider; trocar o par useState e useEffect por useQuery({ queryKey: ["pedidos"], queryFn: buscarPedidos }); tratar os três estados de carregando, erro e sucesso; e usar useMutation com queryClient.invalidateQueries no onSuccess, para a lista se atualizar sozinha. O erro de estreia: usar a mesma queryKey para consultas diferentes, o que faz uma tela mostrar o dado da outra sem nenhum aviso. E o limite da ferramenta: dentro de um Server Component do Next ela sobra, porque a busca acontece no servidor.
Cada dado tem um dono só. O erro que todo iniciante comete é copiar o dado do servidor para dentro de um Zustand ou de um useState e passar a manter duas cópias do mesmo número. Deixe o dado do servidor no cache da biblioteca e guarde no estado local só o que é da tela, como filtro aberto e aba selecionada. Na régua do curso: catálogo fica no servidor, porque a interação o deixa intacto; carrinho fica no navegador, porque muda a cada clique.
Duas técnicas completam o quadro. A atualização otimista: o código atualiza o cache no clique e, se a chamada falhar, devolve o estado anterior — o exemplo do curso é o coração do Instagram, que pinta na hora; use em curtir, marcar e arrastar, e mantenha pagamento fora disso. E o componente de servidor combinado ao cache: o servidor pré-carrega o dado e entrega o cache já preenchido, eliminando o estado de carregamento no primeiro desenho.
Para os estados assíncronos de envio, o curso apresenta os hooks do React 19: useActionState unifica envio, estado pendente e erro num hook só, recebendo uma função assíncrona (estadoAnterior, formData) => novoEstado ligada ao action do <form>; useFormStatus, do react-dom, deixa um botão filho ler o estado do formulário pai sem repasse de props por três níveis; useOptimistic mostra o resultado antes da resposta do servidor e reverte sozinho se a ação falhar; e use() lê uma promise direto no componente, desde que dentro de <Suspense> — idealmente também dentro de um error boundary.
Formulários: teclar sem redesenhar o formulário inteiro
O react-hook-form é uma biblioteca que guarda os valores digitados fora do estado do React, para que teclar num campo deixe o resto do formulário quieto. A régua de adoção do curso é modesta: num campo único de busca com filtro instantâneo, prefira um useState, que resolve com menos código; a biblioteca se justifica a partir de três campos, ou quando o formulário começar a engasgar no celular.
A API que a revisão precisa reconhecer: register liga um <input> HTML ao formulário; handleSubmit valida antes de chamar a função de envio; formState expõe errors, isSubmitting e isValid. No comparativo do curso, o react-hook-form trabalha no modo não controlado; o TanStack Form opera como repositório reativo em que cada campo assina só a fatia que usa; e o Formisch é o não controlado mínimo.
const { register, handleSubmit, formState: { errors, isSubmitting } } =
useForm<Cadastro>({ resolver: zodResolver(cadastroSchema), mode: "onTouched" });O modo de validação é decisão de re-render. O erro de iniciante é mode: "onChange", que valida a cada tecla; o correto na régua do curso é mode: "onTouched", que espera a pessoa sair do campo antes de apontar o erro.
Filtro, aba e busca moram na URL
O quinto lugar de estado é o endereço da tela, e a ferramenta é o nuqs, que faz parâmetros da URL se comportarem como estado do React: useQueryState e useQueryStates, com conversão de tipo. O passo a passo: instalar o nuqs; envolver a aplicação no NuqsAdapter; trocar useState("") por useQueryState("busca"); e, para número, useQueryState("página", parseAsInteger.withDefault(1)). Dado sensível fica fora da barra de endereço. O erro de estreia é esquecer o adaptador na raiz, o que faz o valor nunca chegar ao endereço.
O ganho de negócio que o curso destaca: o cliente manda o link do filtro para um colega, e o suporte reproduz a tela exata de uma reclamação. O guia de menus, abas e paginação retoma essa mesma régua do lado da navegação.
Servidor e navegador no Next.js: a fronteira componente a componente
Na ficha do curso, o Next.js é o framework que transforma React num site inteiro, com endereços, montagem no servidor e publicação prontos. Os componentes de servidor rodam antes de chegar ao navegador e cortam JavaScript; o roteamento é por pasta, com app/precos/page.tsx virando URL e layout.tsx envolvendo as páginas.
O erro clássico do "use client". Na citação do curso: "o erro que todo iniciante comete: escrever "use client" no topo de todo arquivo para calar um aviso do editor. Essa linha manda o componente inteiro para o navegador e joga fora o principal ganho do Next.js. Coloque-a só no componente que de fato precisa de clique ou de estado."
Como revisar o que o agente devolve
A régua de teste do curso cabe numa frase: testar comportamento, o que a pessoa vê e faz, em vez de implementação. Na Testing Library isso significa encontrar os elementos com getByRole — se o teste encontra o botão pelo papel, o leitor de tela também encontra. O Vitest cobre o componente e o Playwright cobre o caminho de ponta a ponta.
- Identifique o padrão do componente e aplique o sinal de reprovação da tabela dos cinco padrões.
- Pergunte de cada estado novo: que tipo de estado é este e onde ele deveria morar? A pergunta custa trinta segundos e evita a reescrita da camada de dados.
- Procure o par
useStatecomuseEffectbuscando dado de servidor: é o sinal de cache reimplementado à mão. - Procure
"use client"no topo de arquivo que dispensa clique e estado. - Em lista, confira a origem da key e o tratamento do caso vazio.
- Em tela que atualiza várias vezes por segundo, rode o teste de um minuto no painel de componentes: pai redesenhando a cada atualização é dado no lugar errado.
O que este guia deixa de fora, e por quê
Este guia deriva exclusivamente dos capítulos do curso que ensinam React, e o curso ensina React como disciplina de revisão e de encomenda. Ficam fora, porque o curso os trata de passagem ou os assume como pré-requisito: a sintaxe do JSX em si; o mecanismo interno de reconciliação; o useEffect como assunto próprio, com dependências e cleanup — ele aparece nas aulas apenas como metade do antipadrão de busca de dados; a API completa do Context (createContext, Provider) passo a passo; useRef, hooks customizados e a dupla useMemo e useCallback em profundidade; roteamento fora do Next.js; o bootstrap de um projeto novo; exemplos completos de teste; a implementação de error boundaries; e a mecânica de Server Actions por trás do useActionState. Quando o trabalho do time esbarrar num desses temas, a fonte é a documentação oficial de cada projeto, e este guia declara a lacuna em vez de preenchê-la por dedução.
Por onde começar
Abra o último componente React que o time recebeu de um agente e aplique três decisões deste guia: identifique qual dos cinco padrões ele é e procure o sinal de reprovação daquele padrão; pergunte de cada estado onde mora a verdade daquele dado, com a tabela de ferramentas ao lado; e procure o par useState com useEffect buscando dado de servidor. O menu Design continua nos guias de ícones, ilustrações, animação e geração de imagens e de menus, abas e paginação, e o vocabulário das aulas mora no glossário.