Communitygithub.com

react-patterns

Patrones de React 18/19 que incluyen disciplina de hooks, límites entre componentes servidor/cliente, Suspense + límites de error, acciones de formulario, obtención de datos, árboles de decisión para gestión de estado y composición accesible. Úselo al escribir o revisar componentes de React.

¿Qué es react-patterns?

Este skill proporciona un conjunto completo de patrones idiomáticos para React 18 y 19, diseñados para ayudar a desarrolladores a construir árboles de componentes robustos, accesibles y de alto rendimiento. Cubre principios esenciales como tratar el renderizado como una función pura de props y estado, mantener los efectos secundarios fuera del renderizado y favorecer la composición sobre la herencia. Incluye directrices detalladas sobre la disciplina de hooks (top-level, nunca condicionales, limpieza de suscripciones) y un árbol de decisión para la ubicación del estado local, contexto y almacenes externos. También aborda la delimitación entre componentes servidor y cliente en RSC, el uso de Suspense y límites de error, la implementación de formularios con acciones de React 19, una matriz de decisión para la obtención de datos, recetas de composición (slots, componentes compuestos, render props), consejos de rendimiento (React.memo, evitar cascadas de renderizado y virtualización de listas) y un enfoque en la accesibilidad primero. Es compatible con cualquier enrutador (React Router, TanStack Router, Next.js App Router, Remix) y apunta a casos de uso generales de React, dejando las particularidades de frameworks específicos a sus respectivas documentaciones.

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

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

Patrones de React

Patrones idiomáticos de React 18/19 para construir árboles de componentes robustos, accesibles y de alto rendimiento.

Cuándo activarlo

  • Al escribir o modificar componentes funcionales de React, hooks personalizados o árboles de componentes
  • Al revisar archivos JSX/TSX
  • Al diseñar la forma del estado o la composición de componentes
  • Al migrar componentes de clase o código antiguo con mucho uso de forwardRef/useEffect
  • Al elegir entre estado local, estado elevado, contexto y almacenes externos
  • Al trabajar con Componentes Servidor / Componentes Cliente (Next.js App Router, RSC)
  • Al implementar formularios con acciones de React 19 o entradas controladas
  • Al conectar la obtención de datos con TanStack Query / SWR / RSC

Principios Fundamentales

1. El Renderizado es una Función Pura de Props y Estado

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

// Malo: estado derivado almacenado por separado
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>;
}

El estado derivado en useEffect añade un ciclo de renderizado, puede desincronizarse y oscurece el flujo de datos.

2. Efectos Secundarios Fuera del Renderizado

Los efectos, mutaciones, llamadas de red y suscripciones viven en los manejadores de eventos o en useEffect, nunca en el cuerpo del renderizado.

3. Composición Sobre Herencia

React no tiene un modelo de herencia para componentes. Componga con children, render props o props de componentes.

Disciplina de Hooks

Consulte rules/react/hooks.md para el conjunto completo de reglas. Destacados:

  • Solo en el nivel superior, nunca condicionales
  • Limpiar cada suscripción, intervalo, listener
  • Usar actualizador funcional (setX(prev => prev + 1)) cuando el nuevo estado depende del anterior
  • Posición predeterminada: no memorizar — añadir useMemo/useCallback solo cuando un perfilador o una cadena de dependencias demuestre que es necesario
  • Extraer un hook personalizado solo cuando la misma secuencia de hooks aparece en 2 o más componentes

Árbol de Decisión para la Ubicación del Estado

¿Usado por un solo componente?
  -> useState dentro de él

¿Usado por el padre + algunos descendientes?
  -> elevar al ancestro común más cercano

¿Usado en ramas distantes Y lecturas de baja frecuencia (tema, autenticación, locale)?
  -> Contexto de React

¿Actualizaciones de alta frecuencia compartidas en todo el árbol?
  -> almacén externo (Zustand, Jotai, Redux Toolkit)

¿Derivado de un servidor?
  -> biblioteca de estado del servidor (TanStack Query, SWR, RSC fetch)

La mayoría de las páginas no necesitan contexto o un almacén global. Resista la abstracción hasta que la elevación duplicada se vuelva dolorosa.

Componentes Servidor / Cliente (RSC)

// Componente Servidor - predeterminado, asíncrono, nunca envía JS para sí mismo
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 con "use client"
"use client";
export function AddToCartButton({ productId }: { productId: string }) {
  const [pending, startTransition] = useTransition();
  return (
    <button
      disabled={pending}
      onClick={() => startTransition(() => addToCart(productId))}
    >
      {pending ? "Agregando..." : "Agregar al carrito"}
    </button>
  );
}

Límites:

  • Servidor -> Cliente: pasar props serializables o children
  • Cliente -> Servidor: invocar Acciones del Servidor a través de <form action={...}> o imperativamente desde manejadores de eventos
  • Nunca importar un Componente Servidor desde un archivo de Componente Cliente — compóngalos a través de children en su lugar

Suspense + Límites de Error

<ErrorBoundary fallback={<ErrorView />}>
  <Suspense fallback={<UserSkeleton />}>
    <UserDetail id={id} />
  </Suspense>
</ErrorBoundary>
  • Coloque los límites de Suspense cerca de los datos, no en la raíz de la ruta — revele el contenido progresivamente
  • Error Boundary sigue siendo una API de clase; use react-error-boundary para un envoltorio compatible con hooks
  • Un límite captura errores lanzados durante el renderizado, el ciclo de vida y los constructores de sus hijos — NO en manejadores de eventos o código asíncrono

Formularios

Acciones de formulario de React 19 (preferido para código nuevo)

"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}>Guardar</button>
      {state.error && <p role="alert">{state.error}</p>}
    </form>
  );
}

Entradas controladas

Use controladas cuando el valor impulse otra UI, formatee en cada pulsación de tecla o implemente validación en tiempo real.

Formularios complejos

Para formularios de varios pasos, matrices de campos dinámicos o validación entre campos: use una biblioteca (React Hook Form, TanStack Form). Gestionar el estado manualmente para formularios más allá de la complejidad trivial es una trampa de mantenimiento.

Matriz de Decisión para la Obtención de Datos

NecesidadHerramienta
Datos por solicitud en Next.js App RouterRSC await fetch()
Caché del lado del cliente + mutaciones + invalidaciónTanStack Query
Caché ligera del cliente + revalidaciónSWR
Suscripciones en tiempo realServer-Sent Events, WebSockets o la API de suscripción de la biblioteca
Disparar y olvidar una sola vezfetch() en un manejador de eventos

Evite useEffect + fetch para datos de aplicación — condiciones de carrera, sin caché, sin reintento, sin integración con Suspense.

Recetas de Composición

Slot a través de children

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

Slots con nombre

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

Componentes compuestos (estado compartido a través de Contexto)

<Tabs defaultValue="profile">
  <Tabs.List>
    <Tabs.Trigger value="profile">Perfil</Tabs.Trigger>
    <Tabs.Trigger value="settings">Ajustes</Tabs.Trigger>
  </Tabs.List>
  <Tabs.Panel value="profile"><Profile /></Tabs.Panel>
  <Tabs.Panel value="settings"><Settings /></Tabs.Panel>
</Tabs>

Render prop / función como hijo

Útil cuando el padre necesita pasar parámetros a la salida renderizada:

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

Alternativa moderna: un hook (useData(id)) que devuelve la misma forma — generalmente más limpio.

Rendimiento

Cuándo React.memo Realmente Ayuda

Envuelva un componente en React.memo solo cuando:

  1. Se vuelve a renderizar con frecuencia
  2. Sus props son generalmente las mismas entre renderizados
  3. Su renderizado es mediblemente costoso

React.memo añade una comprobación de igualdad en cada renderizado. Si las props difieren en la mayoría de los renderizados, la comprobación es pura sobrecarga.

Evitar Cascadas de Renderizado

  • Eleve el estado hacia abajo en lugar de hacia arriba cuando sea posible
  • Divida el contexto: un contexto por preocupación, de modo que un cambio en themeContext no vuelva a renderizar los consumidores de autenticación
  • Use useSyncExternalStore para bibliotecas de estado externas — requerido para un renderizado concurrente seguro

Listas

  • Proporcione props key estables (id de base de datos, no índice de matriz)
  • Virtualice listas largas con @tanstack/react-virtual o react-window una vez que el recuento de elementos visibles supere ~50 con filas no triviales

Composición Accesible

  • Siempre renderice HTML semántico (<button>, <a>, <nav>, <main>) antes de recurrir a atributos role
  • Cada elemento interactivo debe ser accesible por teclado
  • Las entradas de formulario necesitan etiquetas — <label htmlFor> o aria-label si están visualmente etiquetadas por un icono
  • Gestione el foco en cambios de ruta y apertura/cierre de modales
  • Ejecute axe en las pruebas de componentes (consulte skills/react-testing)
  • Enlace cruzado: skills/accessibility/SKILL.md cubre los criterios WCAG y las bibliotecas de patrones

Enrutamiento

Este skill es independiente del enrutador. Los patrones anteriores funcionan con React Router, TanStack Router, Next.js App Router, Remix Router. Los patrones específicos del enrutador (loaders, actions, layouts anidados) siguen la documentación del enrutador — son preocupaciones del framework sobre la base de React.

Fuera del Alcance (Secciones de Referencia)

  • Especificidades de Next.js: Carga de datos de App Router, Route Handlers, Middleware, Parallel Routes — preocupación separada, use la documentación de Next.js
  • React Native: Los patrones específicos de la plataforma difieren lo suficiente como para justificar un skill separado react-native-patterns (aún no presente)
  • Remix: Las convenciones de Loader/action se superponen con RSC pero siguen la documentación de Remix

Relacionados

  • Reglas: rules/react/ — estilo de código, hooks, patrones, seguridad, pruebas
  • Skills: react-performance para el conjunto de reglas de rendimiento derivado de Vercel, frontend-patterns para preocupaciones de UI entre frameworks, accessibility, angular-developer para comparación de frameworks
  • Agentes: react-reviewer para revisión de código, react-build-resolver para errores de construcción/empaquetador
  • Comandos: /react-review, /react-build, /react-test

Ejemplos

Hook personalizado para búsqueda con 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 Optimista con useOptimistic de React 19

"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: "me" });
    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>
    </>
  );
}

Dividiendo contexto para evitar cascadas de renderizado

// Dos contextos: uno cambia raramente, otro frecuentemente
const ThemeContext = createContext<Theme>("light");
const NotificationsContext = createContext<Notification[]>([]);

// Un componente que solo consume ThemeContext NO se vuelve a renderizar cuando cambian las notificaciones

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.

Skills relacionados