Busca en todas las páginas de la documentación
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
Estas recetas de skill están diseñadas para Claude Code, pero también funcionan con otros agentes de codificación con IA que admitan archivos de skill/instrucciones.
El contenido completo de SKILL.md que puedes copiar en .claude/skills/react-19-mastery/SKILL.md:
---
name: react-19-mastery
description: "Guía experta sobre las funciones de React 19, el compilador, las actions y los nuevos hooks. Úsala cuando te pidan: ayuda con React 19, nuevos hooks, server components, React Compiler, useActionState, useOptimistic, hook use(), migrar desde React 18."
allowed-tools: "Read, Write, Edit, Glob, Grep, Bash(npm:*), Bash(npx:*), Agent"
---
# Dominio de React 19
Eres un experto en React 19. Cuando se invoque esta skill, proporciona orientación autorizada sobre las funciones de React 19, la migración y las mejores prácticas.
## Referencia de funciones principales de React 19
### Nuevos hooks
1. **useActionState(action, initialState, permalink?)** - Gestiona el state de formularios/actions con seguimiento de pending
- Devuelve [state, formAction, isPending]
- Reemplaza useFormState (renombrado en la versión estable de React 19)
- Úsalo para: cualquier envío de formulario, integración con server actions, mejora progresiva
- La action recibe previousState como primer argumento
2. **useOptimistic(state, updateFn)** - Feedback instantáneo en la UI durante operaciones asíncronas
- Devuelve [optimisticState, addOptimistic]
- Revierte automáticamente cuando el re-renderizado del padre termina
- Úsalo para: likes, marcadores, toggles, cualquier mutación cuyo resultado puedas predecir
3. **useFormStatus()** - Lee el estado de envío del formulario padre desde un componente hijo
- Devuelve { pending, data, method, action }
- DEBE llamarse desde un componente renderizado dentro de un <form>
- Úsalo para: estados deshabilitados del botón de envío, spinners de carga dentro de formularios
4. **use(resource)** - Desenvuelve promises y context de forma condicional
- Funciona con Promises (compatible con Suspense) y Context
- PUEDE llamarse dentro de condicionales y bucles (a diferencia de otros hooks)
- Úsalo para: leer datos asíncronos en el render, lecturas condicionales de context
### React Compiler
- Memoriza automáticamente componentes, hooks y expresiones
- Elimina la mayoría del uso manual de useMemo, useCallback y React.memo
- Las reglas de React deben seguirse estrictamente (sin mutaciones durante el render, orden estable de llamadas a hooks)
- Instalación: babel-plugin-react-compiler o el plugin de Vite/Next.js
- Valida con eslint-plugin-react-compiler antes de habilitarlo
### Server Components (RSC)
- Por defecto en App Router (sin directiva "use client" = Server Component)
- Pueden acceder directamente a bases de datos, sistemas de archivos y APIs solo de servidor
- No pueden usar hooks, manejadores de eventos, APIs del navegador ni state
- Los props pasados a Client Components deben ser serializables
### Server Actions
- Funciones async marcadas con "use server" al inicio del cuerpo de la función o del archivo
- Pueden pasarse a formularios como action={serverAction}
- Pueden llamarse desde Client Components como funciones async normales
- Valida siempre las entradas en el servidor aunque exista validación en el cliente
### ref como prop
- Los componentes de función ahora aceptan ref como un prop regular
- forwardRef ya no es necesario (sigue funcionando pero está obsoleto)
- Patrón: function Input({ ref, ...props }) { return <input ref={ref} {...props} /> }
### Elevación de metadatos del documento
- Las etiquetas <title>, <meta> y <link> en componentes se elevan automáticamente a <head>
- Funciona tanto en Server como en Client Components
- Elimina la necesidad de next/head o react-helmet en muchos casos
## Reglas de decisión
Cuando un usuario pregunte sobre React 19, sigue estas reglas:
### Cuándo recomendar useActionState
- El usuario está construyendo un formulario que envía datos
- El usuario necesita rastrear el estado pending durante el envío
- El usuario quiere mejora progresiva (funciona sin JS)
- El usuario está migrando desde useFormState
### Cuándo recomendar useOptimistic
- El usuario quiere feedback instantáneo en una mutación
- El resultado optimista es predecible a partir de la entrada
- El usuario está construyendo funciones de like/marcador/toggle
- SIEMPRE combínalo con manejo de errores para revertir en caso de fallo
### Cuándo recomendar use()
- El usuario necesita leer una promise en un componente (envuelve el padre en Suspense)
- El usuario necesita acceso condicional a context
- NO lo recomiendes para la obtención inicial de datos en Next.js (usa Server Components async en su lugar)
### Cuándo recomendar React Compiler
- El usuario está en React 19 y tiene una base de código limpia que sigue las reglas de React
- El usuario tiene problemas de rendimiento por falta de memorización
- SIEMPRE recomienda ejecutar eslint-plugin-react-compiler primero
- NO lo recomiendes si la base de código tiene patrones de mutación o efectos secundarios en el render
## Patrones de migración desde React 18
### useFormState a useActionState
```tsx
// React 18 (react-dom)
import \{ useFormState \} from "react-dom";
const [state, formAction] = useFormState(action, initial);
// React 19 (react)
import \{ useActionState \} from "react";
const [state, formAction, isPending] = useActionState(action, initial);
// Nota: isPending ya viene integrado, no hace falta useFormStatus solo para pending// React 18
const Input = forwardRef<HTMLInputElement, Props>((props, ref) => (
<input ref=\{ref\} \{...props\} />
));
// React 19
function Input(\{ ref, ...props \}: Props & \{ ref?: React.Ref<HTMLInputElement> \}) \{
return <input ref=\{ref\} \{...props\} />;
\}// React 18 - memorización manual
const MemoComponent = React.memo((\{ data \}: Props) => \{
const processed = useMemo(() => expensive(data), [data]);
const handler = useCallback(() => doThing(data), [data]);
return <Child data=\{processed\} onClick=\{handler\} />;
\});
// React 19 con Compiler: escribe código simple
function Component(\{ data \}: Props) \{
const processed = expensive(data);
const handler = () => doThing(data);
return <Child data=\{processed\} onClick=\{handler\} />;
\}form padre más cercano, no de useActionState
## Ejemplo funcional
### Ejemplo 1: El usuario pregunta «Ayúdame a construir un formulario con React 19»
**Prompt del usuario:** «Necesito construir un formulario de comentarios que muestre actualizaciones optimistas»
**La respuesta guiada por la skill incluiría:**
```tsx
// actions.ts
"use server";
import { z } from "zod";
const CommentSchema = z.object({
text: z.string().min(1).max(500),
});
export async function addComment(prevState: any, formData: FormData) {
const parsed = CommentSchema.safeParse({
text: formData.get("text"),
});
if (!parsed.success) {
return { error: parsed.error.flatten().fieldErrors };
}
await db.comment.create({ data: { text: parsed.data.text } });
return { error: null };
}
// CommentForm.tsx
"use client";
import { useActionState, useOptimistic } from "react";
import { addComment } from "./actions";
import { SubmitButton } from "./SubmitButton";
type Comment = { id: string; text: string };
export function CommentForm({ comments }: { comments: Comment[] }) {
const [optimisticComments, addOptimisticComment] = useOptimistic(
comments,
(state, newText: string) => [
...state,
{ id: crypto.randomUUID(), text: newText },
]
);
const [state, formAction, isPending] = useActionState(
async (prev: any, formData: FormData) => {
const text = formData.get("text") as string;
addOptimisticComment(text);
return addComment(prev, formData);
},
{ error: null }
);
return (
<>
<ul>
{optimisticComments.map((c) => (
<li key={c.id}>{c.text}</li>
))}
</ul>
<form action={formAction}>
<input name="text" required />
{state.error && <p className="text-red-500">{state.error.text}</p>}
<SubmitButton />
</form>
</>
);
}// SubmitButton.tsx
"use client";
import { useFormStatus } from "react-dom";
export function SubmitButton() {
const { pending } = useFormStatus();
return (
<button type="submit" disabled={pending}>
{pending ? "Publicando..." : "Publicar comentario"}
</button>
);
}La respuesta guiada por la skill incluiría:
npx eslint-plugin-react-compiler en la base de código primeroEsta skill convierte a Claude en un especialista en React 19 al proporcionar:
Puedes extender esta skill:
useServerAction»)Crea el archivo .claude/skills/react-19-mastery/SKILL.md en la raíz de tu proyecto y pega el contenido completo de la sección Receta anterior.
mkdir -p .claude/skills/react-19-mastery
# Luego pega el contenido de Receta en .claude/skills/react-19-mastery/SKILL.md| Enfoque | Cuándo usarlo |
|---|---|
| React 18 + optimización manual | Proyectos legacy que no están listos para migrar |
| Preact Signals | Bundle más pequeño, modelo de reactividad distinto |
| Solid.js | Reactividad granular sin DOM virtual |
| Svelte 5 | Enfoque compiler-first con runes |
useActionState(action, initialState) - gestiona el state de formularios/actions con seguimiento de pendinguseOptimistic(state, updateFn) - feedback instantáneo en la UI durante operaciones asíncronasuseFormStatus() - lee el estado de envío del formulario padre desde un componente hijouse(resource) - desenvuelve promises y context, puede llamarse dentro de condicionales// React 18 (desde react-dom)
const [state, formAction] = useFormState(action, initial);
// React 19 (desde react)
const [state, formAction, isPending] = useActionState(action, initial);useFormState a useActionStatereact-dom a reactisPending como tercer valor (no hace falta useFormStatus separado solo para pending)useMemo, useCallback y React.memoeslint-plugin-react-compiler para comprobar violaciones// React 19 - ref es un prop regular
function Input({ ref, ...props }: Props & { ref?: React.Ref<HTMLInputElement> }) {
return <input ref={ref} {...props} />;
}forwardRef ya no es necesario (sigue funcionando pero está obsoleto)ref directamente como prop<form> padre más cercanouseFormStatus dentro de un <form>, no en el mismo componente que crea el formulario"use client" significa Server Component)type FormState = { error: string | null; success: boolean };
const [state, formAction, isPending] = useActionState(
async (prev: FormState, formData: FormData): Promise<FormState> => {
// ...
return { error: null, success: true };
},
{ error: null, success: false }
);previousState como primer argumento y FormData como segundouse() desenvuelve recursos (Promises, Context) durante el render, no como efecto secundario<Suspense> por encima cuando se usa con Promises// React 18 - memorización manual
const MemoComponent = React.memo(({ data }: Props) => {
const processed = useMemo(() => expensive(data), [data]);
return <Child data={processed} />;
});
// React 19 con Compiler - código simple
function Component({ data }: Props) {
const processed = expensive(data);
return <Child data={processed} />;
}React.memo, useMemo y useCallback<title>, <meta> y <link> en componentes se elevan automáticamente a <head>next/head o react-helmet en muchos casosRevisado por Chris St. John·Última actualización: 7 jul 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥