Communitygithub.com

react-patterns

Padrões React 18/19 incluindo disciplina de hooks, limites entre componentes servidor/cliente, Suspense + Error Boundaries, ações de formulário, busca de dados, árvore de decisão para gerenciamento de estado e composição com acessibilidade em primeiro lugar. Use ao escrever ou revisar componentes React.

O que é react-patterns?

O skill react-patterns é um guia abrangente de padrões idiomáticos para React 18/19, focado em construir árvores de componentes robustas, acessíveis e performáticas. Ele cobre desde princípios fundamentais como 'render é uma função pura de props e estado' e 'efeitos colaterais fora do render', até tópicos avançados como Componentes Servidor/Cliente (RSC), Suspense e Error Boundaries, formulários com ações do React 19, e uma matriz de decisão para onde colocar o estado (local, estado levantado, contexto ou store externa). O skill é útil para qualquer desenvolvedor React que queira escrever código previsível, evitar armadilhas comuns como derivação de estado em useEffect, e escolher as ferramentas certas para busca de dados (TanStack Query, SWR, RSC fetch) e gerenciamento de formulários complexos. Ele suporta plataformas como Next.js App Router, Remix, React Router e TanStack Router, e inclui exemplos práticos como hooks customizados para busca com debounce, UI otimista com useOptimistic e separação de contextos para evitar cascatas de re-renderização. A documentação também enfatiza acessibilidade e performance, fornecendo regras claras sobre quando usar React.memo, como virtualizar listas longas e como estruturar a composição de componentes com slots, compound components e render props.

Funciona com✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/everything-claude-code/tree/main/skills/react-patterns

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

Padrões React (React Patterns)

Padrões idiomáticos React 18/19 para construir árvores de componentes robustas, acessíveis e performáticas.

Quando Ativar

  • Escrever ou modificar componentes funcionais React, hooks customizados ou árvores de componentes
  • Revisar arquivos JSX/TSX
  • Projetar forma do estado ou composição de componentes
  • Migrar componentes de classe ou código antigo com forwardRef/useEffect
  • Escolher entre estado local, estado levantado, contexto e stores externas
  • Trabalhar com Server Components / Client Components (Next.js App Router, RSC)
  • Implementar formulários com ações do React 19 ou inputs controlados
  • Conectar busca de dados com TanStack Query / SWR / RSC

Princípios Fundamentais

1. Render é uma Função Pura de Props e Estado

// Bom: deriva durante o render
function Cart({ items }: { items: CartItem[] }) {
  const total = items.reduce((sum, i) => sum + i.price * i.qty, 0);
  return <span>{formatMoney(total)}</span>;
}

// Ruim: estado derivado armazenado separadamente
function Cart({ items }: { items: CartItem[] }) {
  const [total, setTotal] = useState(0);
  useEffect(() => {
    setTotal(items.reduce((sum, i) => sum + i.price * i.qty, 0));
  }, [items]);
  return <span>{formatMoney(total)}</span>;
}

Estado derivado em useEffect adiciona um ciclo de render, pode dessincronizar e obscurece o fluxo de dados.

2. Efeitos Colaterais Fora do Render

Efeitos, mutações, chamadas de rede e inscrições vivem em manipuladores de eventos ou useEffect — nunca no corpo do render.

3. Composição Sobre Herança

React não tem modelo de herança para componentes. Compõe com children, render props ou props de componente.

Disciplina de Hooks

Consulte rules/react/hooks.md para o conjunto completo de regras. Destaques:

  • Apenas no nível superior, nunca condicional
  • Limpar toda inscrição, intervalo, listener
  • Atualizador funcional (setX(prev => prev + 1)) quando o novo estado depende do anterior
  • Posição padrão: não memoizar — adicione useMemo/useCallback apenas quando um profiler ou uma cadeia de dependências provar que é necessário
  • Extrair um hook customizado apenas quando a mesma sequência de hooks aparece em 2+ componentes

Árvore de Decisão para Localização do Estado

Usado por um componente?
  -> useState dentro dele

Usado pelo pai + alguns descendentes?
  -> levantar para o ancestral comum mais próximo

Usado em ramos distantes E leituras de baixa frequência (tema, autenticação, localidade)?
  -> React Context

Atualizações de alta frequência compartilhadas pela árvore?
  -> store externa (Zustand, Jotai, Redux Toolkit)

Derivado de um servidor?
  -> biblioteca de estado do servidor (TanStack Query, SWR, RSC fetch)

A maioria das páginas não precisa de contexto ou store global. Resista à abstração até que levantar estado se torne doloroso.

Componentes Servidor / Cliente (RSC)

// Componente Servidor - padrão, assíncrono, nunca envia JavaScript para si mesmo
export default async function ProductPage({ params }: { params: { id: string } }) {
  const product = await db.product.findUnique({ where: { id: params.id } });
  if (!product) notFound();
  return <ProductView product={product} />;
}

// Componente Cliente - opt-in com "use client"
"use client";
export function AddToCartButton({ productId }: { productId: string }) {
  const [pending, startTransition] = useTransition();
  return (
    <button
      disabled={pending}
      onClick={() => startTransition(() => addToCart(productId))}
    >
      {pending ? "Adicionando..." : "Adicionar ao carrinho"}
    </button>
  );
}

Limites:

  • Servidor -> Cliente: passar props serializáveis ou children
  • Cliente -> Servidor: invocar Server Actions via <form action={...}> ou imperativamente a partir de manipuladores de eventos
  • Nunca import um Componente Servidor de um arquivo de Componente Cliente — compõe via children

Suspense + Error Boundaries

<ErrorBoundary fallback={<ErrorView />}>
  <Suspense fallback={<UserSkeleton />}>
    <UserDetail id={id} />
  </Suspense>
</ErrorBoundary>
  • Coloque limites Suspense próximos aos dados, não na raiz da rota — revele conteúdo progressivamente
  • Error Boundary continua sendo uma API de classe; use react-error-boundary para um wrapper amigável a hooks
  • Um boundary captura erros lançados durante render, ciclo de vida e construtores de seus filhos — NÃO em manipuladores de eventos ou código assíncrono

Formulários

Ações de formulário do React 19 (preferido para código novo)

"use client";
import { useActionState } from "react";

const initial = { error: null as string | null };

async function updateUserAction(_prev: typeof initial, formData: FormData) {
  "use server";
  const parsed = UserSchema.safeParse(Object.fromEntries(formData));
  if (!parsed.success) return { error: "Entrada inválida" };
  await db.user.update({ where: { id: parsed.data.id }, data: parsed.data });
  return { error: null };
}

export function UserForm() {
  const [state, formAction, pending] = useActionState(updateUserAction, initial);
  return (
    <form action={formAction}>
      <input name="name" required />
      <button type="submit" disabled={pending}>Salvar</button>
      {state.error && <p role="alert">{state.error}</p>}
    </form>
  );
}

Inputs controlados

Use controle quando o valor dirige outra UI, formata a cada tecla ou implementa validação em tempo real.

Formulários complexos

Para formulários de múltiplas etapas, campos dinâmicos ou validação entre campos: use uma biblioteca (React Hook Form, TanStack Form). Gerenciar estado manualmente para formulários além da simplicidade trivial é uma armadilha de manutenção.

Matriz de Decisão para Busca de Dados

NecessidadeFerramenta
Dados por requisição no Next.js App RouterRSC await fetch()
Cache + mutações + invalidação no clienteTanStack Query
Cache leve + revalidação no clienteSWR
Inscrições em tempo realServer-Sent Events, WebSockets ou API de inscrição da biblioteca
Única vez e esquecefetch() em um manipulador de eventos

Evite useEffect + fetch para dados de aplicação — condições de corrida, sem cache, sem retentativa, sem integração com Suspense.

Receitas de Composição

Slot via children

<Layout>
  <Header />
  <Main>{content}</Main>
</Layout>

Slots nomeados

<Page header={<Nav />} sidebar={<Filters />}>
  <Results />
</Page>

Componentes compostos (estado compartilhado via Context)

<Tabs defaultValue="profile">
  <Tabs.List>
    <Tabs.Trigger value="profile">Perfil</Tabs.Trigger>
    <Tabs.Trigger value="settings">Configurações</Tabs.Trigger>
  </Tabs.List>
  <Tabs.Panel value="profile"><Profile /></Tabs.Panel>
  <Tabs.Panel value="settings"><Settings /></Tabs.Panel>
</Tabs>

Render prop / função-como-filho

Útil quando o pai precisa passar parâmetros para a saída renderizada:

<DataLoader id={id}>
  {({ data, isLoading }) => isLoading ? <Spinner /> : <UserCard user={data} />}
</DataLoader>

Alternativa moderna: um hook (useData(id)) retornando a mesma forma — geralmente mais limpo.

Performance

Quando React.memo Realmente Ajuda

Envolva um componente em React.memo apenas quando:

  1. Ele re-renderiza frequentemente
  2. Suas props são geralmente as mesmas entre renders
  3. Seu render é mensuravelmente caro

React.memo adiciona uma verificação de igualdade em cada render. Se as props diferirem na maioria dos renders, a verificação é pura sobrecarga.

Evitando Cascatas de Render

  • Levante o estado para baixo em vez de para cima, quando possível
  • Divida o contexto: um contexto por preocupação, para que uma mudança em themeContext não re-renderize consumidores de autenticação
  • Use useSyncExternalStore para bibliotecas de estado externas — necessário para renderização concorrente segura

Listas

  • Forneça props key estáveis (id do banco de dados, não índice do array)
  • Virtualize listas longas com @tanstack/react-virtual ou react-window assim que a contagem de itens visíveis exceder ~50 com linhas não triviais

Composição com Acessibilidade em Primeiro Lugar

  • Sempre renderize HTML semântico (<button>, <a>, <nav>, <main>) antes de recorrer a atributos role
  • Todo elemento interativo deve ser alcançável por teclado
  • Inputs de formulário precisam de labels — <label htmlFor> ou aria-label se visualmente rotulado por um ícone
  • Gerencie o foco em mudanças de rota e abertura/fechamento de modal
  • Execute axe em testes de componentes (consulte skills/react-testing)
  • Link cruzado: skills/accessibility/SKILL.md cobre critérios WCAG e bibliotecas de padrões

Roteamento

Este skill é independente de roteador. Os padrões acima funcionam com React Router, TanStack Router, Next.js App Router, Remix Router. Padrões específicos de roteador (loaders, actions, layouts aninhados) seguem a documentação do roteador — são preocupações de framework sobrepostas ao núcleo do React.

Fora do Escopo (Seções de Ponteiro)

  • Especificidades do Next.js: Carregamento de dados do App Router, Route Handlers, Middleware, Rotas Paralelas — preocupação separada, use a documentação do Next.js
  • React Native: Padrões específicos de plataforma diferem o suficiente para justificar um skill separado react-native-patterns (ainda não presente)
  • Remix: Convenções de loader/action se sobrepõem ao RSC, mas seguem a documentação do Remix

Relacionados

  • Regras: rules/react/ — estilo de código, hooks, padrões, segurança, teste
  • Skills: react-performance para o conjunto de regras de performance derivado da Vercel, frontend-patterns para preocupações de UI entre frameworks, accessibility, angular-developer para comparação de frameworks
  • Agentes: react-reviewer para revisão de código, react-build-resolver para erros de build/bundler
  • Comandos: /react-review, /react-build, /react-test

Exemplos

Hook customizado para busca com debounce

function useDebounce<T>(value: T, delay = 300): T {
  const [debounced, setDebounced] = useState(value);
  useEffect(() => {
    const id = setTimeout(() => setDebounced(value), delay);
    return () => clearTimeout(id);
  }, [value, delay]);
  return debounced;
}

function SearchBox() {
  const [query, setQuery] = useState("");
  const debounced = useDebounce(query, 300);
  const { data } = useQuery({
    queryKey: ["search", debounced],
    queryFn: () => searchApi(debounced),
    enabled: debounced.length > 0,
  });
  return (
    <>
      <input value={query} onChange={(e) => setQuery(e.target.value)} />
      <Results items={data ?? []} />
    </>
  );
}

UI otimista com React 19 useOptimistic

"use client";
import { useOptimistic } from "react";

export function MessageList({ messages }: { messages: Message[] }) {
  const [optimistic, addOptimistic] = useOptimistic(
    messages,
    (state, newMessage: Message) => [...state, newMessage],
  );

  async function send(formData: FormData) {
    const text = String(formData.get("text"));
    addOptimistic({ id: "pending", text, sender: "eu" });
    await saveMessage(text);
  }

  return (
    <>
      <ul>{optimistic.map((m) => <li key={m.id}>{m.text}</li>)}</ul>
      <form action={send}>
        <input name="text" />
        <button type="submit">Enviar</button>
      </form>
    </>
  );
}

Dividindo contexto para evitar cascatas de render

// Dois contextos: um raramente muda, o outro frequentemente
const ThemeContext = createContext<Theme>("light");
const NotificationsContext = createContext<Notification[]>([]);

// Um componente que consome apenas ThemeContext NÃO re-renderiza quando as notificações mudam

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

accessibility

Design, implement, and audit inclusive digital products using WCAG 2.2 Level AA. Use when building or auditing UI that must meet WCAG 2.2 Level AA, or when reviewing a change for keyboard, contrast, or screen-reader support.

affaan-m/claude-api

Anthropic Claude API patterns for Python and TypeScript. Covers Messages API, streaming, tool use, vision, extended thinking, batches, prompt caching, and Claude Agent SDK. Use when building applications with the Claude API or Anthropic SDKs.

affaan-m/everything-claude-code

End-to-end marketing campaign planning and execution. Covers audience research, positioning, campaign angle definition, landing page copy, email sequences, social posts, ad copy, short-form video scripts, and content calendars. Use as the orchestration layer for multi-channel product launches. Use when planning or executing a multi-channel product launch, or producing landing page, email, social, or ad copy.

affaan-m/everything-claude-code

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/everything-claude-code-conventions

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/frontend-design

Create distinctive, production-grade frontend interfaces with high design quality. Use when the user asks to build web components, pages, or applications and the visual direction matters as much as the code quality.

affaan-m/gget

gget CLI and Python workflow for quick genomic database queries, sequence lookup, BLAST-style searches, enrichment checks, and reproducible bioinformatics evidence logs.

affaan-m/literature-review

Systematic literature-review workflow for academic, biomedical, technical, and scientific topics, including search planning, source screening, synthesis, citation checks, and evidence logging.

affaan-m/motion-ui

Production-ready UI motion system for React/Next.js. Use when implementing animations, transitions, or motion patterns.

affaan-m/project-guidelines-example

Example project-specific skill template based on a real production application.

affaan-m/pubmed-database

Direct PubMed and NCBI E-utilities search workflows for biomedical literature, MeSH queries, PMID lookup, citation retrieval, and API-backed literature monitoring.

affaan-m/scholar-evaluation

Structured scholarly-work evaluation for papers, proposals, literature reviews, methods sections, evidence quality, citation support, and research-writing feedback.

affaan-m/uspto-database

USPTO patent and trademark data workflow for official record lookup, PatentSearch queries, TSDR checks, assignment data, and reproducible IP research logs.

agent-architecture-audit

Full-stack diagnostic for agent and LLM applications. Audits the 12-layer agent stack for wrapper regression, memory pollution, tool discipline failures, hidden repair loops, and rendering corruption. Produces severity-ranked findings with code-first fixes. Essential for developers building agent applications, autonomous loops, or any LLM-powered feature. Use when an agent or LLM feature misbehaves and the failing layer is unknown, or before shipping an agent stack.

agent-eval

Head-to-head comparison of coding agents (Claude Code, Aider, Codex, etc.) on custom tasks with pass rate, cost, time, and consistency metrics. Use when choosing between coding agents, or when a change to an agent setup needs measured pass rate, cost, and time rather than an impression.

agent-harness-construction

Design and optimize AI agent action spaces, tool definitions, and observation formatting for higher completion rates. Use when defining or revising an agent

agentic-engineering

Operate as an agentic engineer using eval-first execution, decomposition, and cost-aware model routing. Use when planning or executing engineering work that agents will carry out end to end.

agentic-os

Build persistent multi-agent operating systems on Claude Code. Covers kernel architecture, specialist agents, slash commands, file-based memory, scheduled automation, and state management without external databases. Use when building a persistent multi-agent system on Claude Code with its own memory, commands, and scheduling.

agent-introspection-debugging

Structured self-debugging workflow for AI agent failures using capture, diagnosis, contained recovery, and introspection reports. Use when an agent run fails and you need a reproducible diagnosis instead of a retry.

agent-payment-x402

Add x402 payment execution to AI agents with per-task budgets, spending controls, and non-custodial wallets. Supports Base through agentwallet-sdk and X Layer through OKX Payments / OKX Agent Payments Protocol. Use when an agent must pay for something itself and needs per-task budgets, spending controls, and a non-custodial wallet.

Habilidades Relacionadas