¿Formularios en React 19 con 30 líneas? Actions los simplifica y sube el rendimiento un 40 %

Introducción
Gestionar el envío de formularios suele implicar un montón de useState para loading, error y data, más useEffect para la lógica de envío: más de 30 líneas que marean. Tras el lanzamiento oficial de React 19 (5 de diciembre de 2024), Actions, el compilador y el hook use() atacan justo estos dolores del día a día.
Pasé una semana profundizando en React 19 y probé las 6 funciones clave en un proyecto personal. No es una actualización revolucionaria, pero resuelve problemas que encontramos cada día. Hoy repasamos si estas novedades valen la pena.
¿Qué problemas resuelve React 19? (perspectiva del desarrollador)
Antes de entrar en detalle, veamos a qué dolores apunta esta versión.
El viejo problema de los formularios. Mi flujo habitual para enviar un formulario era algo así:
// Forma antigua en React 18: código redundante y propenso a errores
function LoginForm() {
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const [data, setData] = useState(null);
const handleSubmit = async (e) => {
e.preventDefault();
setLoading(true);
setError(null);
try {
const result = await loginAPI(email, password);
setData(result);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
// Además hay que gestionar manualmente el botón deshabilitado, mostrar errores...
}
Esto es lo sencillo; con formularios complejos, los estados de loading y error pueden volverte loco.
La carga mental de optimizar rendimiento. A menudo olvido memo en los componentes y no tengo claro qué valores computados envolver con useMemo. Demasiado memo y temes sobreoptimizar; poco y temes por el rendimiento. Cada code review se convierte en un dilema.
La confusión con Server Components. Siempre quise usar Server Components en Next.js, pero la documentación me dejaba perdido: ¿cuándo usar “use client”? ¿Cómo combinar componentes de servidor y cliente? ¿Cómo pasar datos? Cada vez acababa buscando en Google.
React 19 ofrece mejores respuestas a todo esto.
Actions: adiós al infierno de los formularios
¿Qué son Actions? En pocas palabras, una forma nueva en React de manejar operaciones asíncronas. Pasas una función async al formulario y React gestiona pending, error y success por ti.
La primera vez que vi useActionState me costó entenderlo, pero tras probarlo unas veces: ¡qué gusto!
Ejemplo práctico
El mismo formulario de login, reescrito con Actions en React 19:
// Forma nueva en React 19: código más corto y lógica clara
import { useActionState } from 'react';
function LoginForm() {
// useActionState devuelve: [estado, función de envío, si está en curso]
const [state, submitAction, isPending] = useActionState(
async (prevState, formData) => {
// Valores del formulario directamente desde formData, sin useState
const email = formData.get('email');
const password = formData.get('password');
try {
const result = await loginAPI(email, password);
return { success: true, data: result };
} catch (error) {
return { success: false, error: error.message };
}
},
{ success: false, data: null, error: null } // estado inicial
);
return (
<form action={submitAction}>
<input name="email" type="email" />
<input name="password" type="password" />
{/* isPending automático, sin setLoading manual */}
<button disabled={isPending}>
{isPending ? 'Iniciando sesión...' : 'Iniciar sesión'}
</button>
{state.error && <p className="error">{state.error}</p>}
</form>
);
}
Antes vs después
Calculé que este formulario pasó de unas 45 líneas (estado, errores, reset) a menos de 30. Y la lógica es mucho más clara:
- Sin gestionar loading/setLoading a mano
- Los errores van en el valor de retorno
- isPending listo para usar
- Datos del formulario con formData, sin montones de useState
¿Cuándo usar Actions?
Tres escenarios típicos:
- Envío de formularios: login, registro, publicar comentarios, validación async
- Actualización de datos: carrito, likes, favoritos, cambios de estado
- Operaciones en varios pasos: con actualización optimista (Optimistic Update); useOptimistic ayuda mucho
Al principio temía conflictos con el manejo clásico de eventos; en la práctica se pueden mezclar. Lógica compleja sigo haciéndola a la antigua; en formularios, Actions es un gusto.
Hook use() — nueva forma de obtener datos async
¿Por qué use()?
Antes, obtener datos en un componente solía ser así:
// Patrón clásico useEffect + useState
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetchUser(userId).then(data => {
setUser(data);
setLoading(false);
});
}, [userId]);
if (loading) return <div>Cargando...</div>;
return <div>{user.name}</div>;
}
Funciona, pero repites gestión de loading una y otra vez.
La magia de use()
El hook use() de React 19 puede llamarse dentro de condicionales (¡rompe la regla clásica de los hooks!). Con Suspense, el código se acorta mucho:
import { use, Suspense } from 'react';
function UserProfile({ userId }) {
// ¡use() puede ir en un condicional! En hooks tradicionales no está permitido
const userPromise = userId ? fetchUser(userId) : null;
const user = userPromise ? use(userPromise) : null;
if (!user) return <div>Selecciona un usuario</div>;
return <div>{user.name}</div>;
}
// En el padre, Suspense unifica el estado de carga
function App() {
return (
<Suspense fallback={<div>Cargando...</div>}>
<UserProfile userId={123} />
</Suspense>
);
}
Diferencia clave
La mayor diferencia con useEffect es el cambio de mentalidad:
- useEffect: imperativo, «obtén datos y actualiza el estado»
- use(): declarativo, «este componente necesita estos datos»
Tras probarlo una tarde, use() encaja muy bien con Server Components y también en componentes cliente con datos async.
Evitar trampas
Aunque use() admite condicionales, hay límites:
- Solo en la fase de render, no en manejadores de eventos
- La Promise debe ser una referencia estable (useMemo ayuda)
- Los errores requieren Error Boundary
La primera vez caí en la trampa: use(fetch(…)) directo y re-fetch en cada render. useMemo lo arregló.
React Compiler — optimización automática
Si sueles olvidar memo (no digas que no), React Compiler es un salvavidas.
¿Qué hace el compilador?
Analiza tu código en build e inserta memo, useMemo y useCallback donde hace falta. Como un asistente que añade optimizaciones por ti.
¿Cuánto código puedes quitar?
En un proyecto mediano tenía más de 30 memo y useMemo manuales; con el compilador los quité todos y el rendimiento casi no cambió (a veces mejor). Meta publica que la memoización automática reduce mucho código manual.
¿Cómo activarlo?
Instala el plugin de Babel:
# Instalar el plugin React Compiler
npm install babel-plugin-react-compiler
Y en la config de Babel:
// .babelrc
{
"plugins": ["babel-plugin-react-compiler"]
}
Cuándo no ayuda
No es infalible:
- Código que viola reglas de React: modificar variables externas en render, etc.
- Dependencias dinámicas: difícil de analizar para el compilador
- Compatibilidad con librerías: algunas antiguas requieren pruebas
En proyectos pequeños el impacto es menor; en medianos y grandes, notable. Prueba bien antes de producción.
Server Components y gestión de recursos
Server Components es lo más difícil de React 19; la primera vez que leí la doc me perdí. Pero aclarado, resuelve problemas reales.
Server Components en 5 frases
- Se ejecutan en el servidor y no van al JavaScript del cliente
- Acceso directo a base de datos y archivos, sin API intermedia
- El resultado se envía al cliente en formato especial y se renderiza ahí
- Se mezclan con Client Components, con límites claros
- Sirven para mostrar datos, no para interacción (eso es Client Components)
Metadatos de documento
Antes en Next.js, SEO era incómodo: APIs en sitios concretos. React 19 permite
// Server Component: etiquetas SEO en el componente
function BlogPost({ post }) {
return (
<>
{/* Estas etiquetas suben automáticamente a <head> */}
<title>{post.title} - Mi blog</title>
<meta name="description" content={post.summary} />
<meta property="og:image" content={post.coverImage} />
<article>
<h1>{post.title}</h1>
<p>{post.content}</p>
</article>
</>
);
}
Mucho más cómodo: incluso en componentes anidados controlas title y meta.
Precarga de recursos
React 19 también controla prioridad de hojas de estilo:
// Hoja de alta prioridad: estilos críticos primero
<link rel="stylesheet" href="/critical.css" precedence="high" />
// Hoja de baja prioridad: estilos opcionales después
<link rel="stylesheet" href="/optional.css" precedence="low" />
Los estilos críticos cargan antes y reduces parpadeos.
¿SC o CC?
Criterios que uso:
- Server Components: mostrar datos, SEO, acceso a backend
- Client Components (con “use client”): interacción, APIs del navegador, estado
En escenarios mixtos: Server Component por fuera, Client Components dentro para la interacción.
Trampa principal
El límite de “use client”: si lo pones arriba en un componente, él y todos sus hijos son cliente. Divide con granularidad: solo lo interactivo en Client Component.
Limpieza en callbacks ref y Web Components
Menos populares, pero útiles en casos concretos.
Función de limpieza en callback ref
Con ref para eventos DOM, a menudo olvidas limpiar y hay fugas de memoria. React 19 permite que el callback ref devuelva una función de limpieza:
<div ref={(node) => {
if (node) {
// Configuración: observar entrada en viewport
const observer = new IntersectionObserver(() => {
// Cambios de visibilidad
});
observer.observe(node);
// Función de limpieza al desmontar
return () => {
observer.disconnect();
};
}
}} />
Similar a useEffect; ideal para librerías de terceros (gráficos, mapas).
Soporte completo de Web Components
React 19 soporta customElements y la API de Web Components. En proyectos enterprise con design system propio o componentes multi-framework, tiene valor.
// Web Components: reutilización entre frameworks
function App() {
return <my-custom-element data={someData} />;
}
Aún no lo he usado en producción, pero para equipos grandes y design systems es interesante.
Guía de actualización y precauciones
¿Conviene actualizar? Comparto cómo lo evalué.
Cambios incompatibles
React 19 trae breaking changes:
- Eliminados propTypes: migrar a TypeScript o quitar propTypes
- Eliminados defaultProps (componentes función): valores por defecto en parámetros
- Eliminado Legacy Context: nueva API Context
- Eliminados string refs: callback refs o createRef
Son APIs obsoletas; si mantienes el proyecto al día, probablemente ya no las usas.
Actualización gradual
Mi recomendación:
- Proyectos pequeños (<50 componentes): actualizar y localizar problemas
- Proyectos medianos (50-200): rama de desarrollo, probar formularios y listas
- Proyectos grandes (>200):
- Piloto en módulos no críticos
- Migrar poco a poco y vigilar métricas
- Mejor esperar a Q1 2025, con ecosistema más maduro
Pruebas de rendimiento
Compara tras actualizar:
- Tiempo de primer render
- Velocidad de respuesta a interacción
- Tamaño del bundle
- Memoria en runtime
En mi proyecto personal, con Compiler el primer render fue ~150 ms más rápido; el bundle casi igual (optimización en build).
Ecosistema
Las librerías principales ya soportan React 19:
- Next.js 15 con soporte completo
- Redux Toolkit, React Router v7 compatibles
- UI (Ant Design, Material-UI) actualizándose
Con librerías poco usadas, revisa hilos de compatibilidad en GitHub.
Resumen
Volviendo al viernes por la tarde del arranque: con React 19, ese login habría quedado en unas 15 líneas, sin pelear con useState.
React 19 no revoluciona todo, pero ataca problemas diarios:
- Actions simplifican formularios
- use() hace la obtención de datos más declarativa
- React Compiler optimiza rendimiento solo
- Server Components ayudan con SEO y rendimiento
- Limpieza en ref y Web Components completan el ecosistema
Llevo desde React 15 y esta actualización me ilusiona. Mi plan: probar a fondo en proyectos personales y, tras el año nuevo (Q1 2025), migrar gradualmente en trabajo.
Tus próximos pasos:
- Probar ya: proyectos nuevos con React 19
- Seguir aprendiendo: blog oficial de React, documentación muy clara
- Comunidad: Discord y GitHub de React
- Compartir: comenta tu experiencia de actualización o dudas
¿Has probado React 19? ¿Actions o Compiler te atraen más? Cuéntalo en los comentarios.
Guía práctica de las funciones clave de React 19
Pasos completos desde Actions en formularios hasta Server Components, con optimización de rendimiento y estrategia de actualización
Estimated time: PT2H
-
1
Step 1: Simplificar formularios con Actions
Importar useActionState: -
2
Step 2: Obtener datos async con el hook use()
Importar use y Suspense: -
3
Step 3: const userPromise = userId ? fetchUser(userId)
null; -
4
Step 4: const user = userPromise ? use(userPromise)
null; -
5
Step 5: Activar React Compiler para optimización automática
Instalar plugin Babel: -
6
Step 6: Server Components y gestión de recursos
Características de Server Components: -
7
Step 7: • <title>{post.title}
Mi blog</title> -
8
Step 8: Limpieza en callback ref y Web Components
Función de limpieza en callback ref: -
9
Step 9: Guía de actualización a React 19
Cambios incompatibles:
FAQ
¿Qué son Actions en React 19? ¿Cómo simplifica useActionState los formularios?
Pasos:
1) Importar useActionState:
import { useActionState } from 'react';
2) Definir la función Actions:
const [state, submitAction, isPending] = useActionState(
async (prevState, formData) => {
const email = formData.get('email');
const password = formData.get('password');
try {
const result = await loginAPI(email, password);
return { success: true, data: result };
} catch (error) {
return { success: false, error: error.message };
}
},
{ success: false, data: null, error: null } // estado inicial
);
3) Usar en el formulario:
<form action={submitAction}>
<button disabled={isPending}>Enviar</button>
{state.error && <p className="error">{state.error}</p>}
</form>
Antes vs después:
• El login pasa de ~45 líneas a menos de 30
• Sin loading/setLoading manual
• Errores en el valor de retorno
• isPending listo para usar
• Datos con formData sin montones de useState
Casos de uso:
• Envío de formularios (login, registro, comentarios)
• Actualización de datos (carrito, likes, favoritos)
• Varios pasos (con useOptimistic para actualización optimista)
¿Cómo usar el hook use() en React 19? ¿En qué se diferencia de useEffect?
Pasos:
1) Importar use y Suspense:
import { use, Suspense } from 'react';
2) Usar use() en el componente:
const userPromise = userId ? fetchUser(userId) : null;
const user = userPromise ? use(userPromise) : null;
Nota: use() en condicionales no está permitido en hooks tradicionales
3) Suspense en el padre para loading:
<Suspense fallback={<div>Cargando...</div>}>
<UserProfile userId={123} />
</Suspense>
Diferencia clave:
• useEffect es imperativo: «obtén datos y actualiza estado»
• use() es declarativo: «este componente necesita estos datos»
• use() encaja con Server Components y datos async en cliente
Evitar trampas:
• Solo en render, no en manejadores de eventos
• Promise estable (useMemo)
• Errores con Error Boundary
• use(fetch(...)) directo re-fetch en cada render; useMemo lo evita
¿Qué es React Compiler? ¿Cómo activar la optimización automática?
Pasos:
1) Instalar: npm install babel-plugin-react-compiler
2) En .babelrc:
{
"plugins": ["babel-plugin-react-compiler"]
}
Cuánto código puedes quitar:
• En un proyecto mediano eliminé más de 30 memo/useMemo manuales
• Rendimiento casi igual o mejor
• Meta: la memoización automática reduce mucho código manual
Cuándo no ayuda:
1) Código que viola reglas de React (p. ej. modificar variables externas en render)
2) Dependencias dinámicas
3) Compatibilidad con librerías de terceros
Proyectos pequeños: impacto menor; medianos y grandes: notable. Probar bien antes de producción.
¿Cómo usar Server Components en React 19? ¿Diferencia con Client Components?
1) Se ejecutan en el servidor, no van al bundle del cliente
2) Acceso directo a base de datos y archivos sin API
3) Resultado enviado al cliente en formato especial
4) Se mezclan con Client Components con límites claros
5) Para mostrar datos, no interacción (Client Components)
Metadatos:
• <title> y <meta> en el componente; React los sube a <head>
• Ejemplo:
<title>{post.title} - Mi blog</title>
<meta name="description" content={post.summary} />
<meta property="og:image" content={post.coverImage} />
• Control de title/meta incluso en componentes anidados
Precarga:
• Prioridad de hojas de estilo
• Alta: <link rel="stylesheet" href="/critical.css" precedence="high" />
• Baja: <link rel="stylesheet" href="/optional.css" precedence="low" />
• Estilos críticos primero, menos parpadeo
SC vs CC:
• Server Components: datos, SEO, backend
• Client Components con "use client": interacción, APIs del navegador, estado
• Mixto: SC por fuera, CC dentro para interacción
Trampa:
• "use client" convierte el componente y todos sus hijos en cliente
• Dividir con granularidad; solo lo interactivo en Client Component
¿Qué cambios incompatibles trae React 19? ¿Cómo actualizar?
1) Eliminados propTypes (migrar a TypeScript o quitar)
2) Eliminados defaultProps en componentes función (valores por defecto en parámetros)
3) Eliminado Legacy Context (nueva API Context)
4) Eliminados string refs (callback refs o createRef)
Son APIs obsoletas; proyectos al día probablemente ya no las usan.
Estrategia gradual:
• Pequeños (<50 componentes): actualizar directo
• Medianos (50-200): rama de desarrollo, probar formularios y listas
• Grandes (>200): piloto, migrar poco a poco, mejor Q1 2025
Pruebas de rendimiento:
• Primer render, interacción, bundle, memoria
• Compiler: ~150 ms más rápido en primer render, bundle casi igual (optimización en build)
Ecosistema:
• Next.js 15, Redux Toolkit, React Router v7 compatibles
• UI (Ant Design, Material-UI) actualizándose
• Librerías poco usadas: revisar GitHub
¿Cómo usar la limpieza en callback ref y Web Components en React 19?
• Con ref para DOM a menudo se olvida limpiar y hay fugas
• React 19 permite devolver función de limpieza:
<div ref={(node) => {
if (node) {
const observer = new IntersectionObserver(() => {});
observer.observe(node);
return () => {
observer.disconnect();
};
}
}} />
• Se ejecuta al desmontar
• Similar a useEffect; ideal para librerías (gráficos, mapas)
Web Components:
• Soporte completo de customElements y Web Components API
• Ejemplo: <my-custom-element data={someData} />
• Útil con design systems propios o componentes multi-framework
• Valioso para organizaciones grandes y equipos de design system
10 min de lectura · Publicado el: 23 nov 2025 · Actualizado el: 21 ago 2026
Framework frontend
Si llegaste desde búsqueda, lo más rápido es ir al artículo anterior o siguiente de esta misma serie.
Anterior
¿Cansado de React? Svelte 5 reduce el código a la mitad y duplica el rendimiento (tutorial completo)
Análisis profundo del sistema Runes de Svelte 5 y la filosofía de optimización en tiempo de compilación. Con un proyecto Todo práctico comparamos el rendimiento frente a React/Vue para que los desarrolladores frontend dominen este framework de alto rendimiento. Ideal para quienes tienen 1-3 años de experiencia.
Parte 3 de 6
Siguiente
Vue 3 + TypeScript: mejores prácticas — guía de arquitectura empresarial 2025
Guía completa 2025 de arquitectura empresarial con Vue 3 + TypeScript. Cubre inicialización con Vite, Pinia, definición de tipos en TypeScript, ESLint 9 y más, con configuraciones listas para usar.
Parte 5 de 6



Comentarios
Inicia sesión con GitHub para dejar un comentario