Pular para o conteúdo
Guia de execução · menu Design

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:

Tipo de estadoExemploFerramentaEvite
LocalAba de um cartão, campo abertouseState ou useReducerBiblioteca global
DerivadoTotal, lista filtradaCalcular na renderização; useMemo só se caroGuardar em useState
Compartilhado, baixa frequênciaTema, sessão, modal globalContext com useReducerStore pesado
Compartilhado, alta frequênciaCarrinho, estado de funcionalidadeZustand, com seletores e useShallowContext, que re-renderiza em cascata
Compartilhado, granularFormulário ou editor complexoJotai, por átomosUm store monolítico
Filtro, aba, paginação, busca?busca=...&página=2nuqs, estado na URLuseState que some no recarregamento
De servidorLista de produtos, perfilTanStack Query ou Server ComponentuseState com useEffect
Fonte externaTamanho da janela, store própriouseSyncExternalStoreuseEffect 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.

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.