Hook: useFormStatus
Introducción
useFormStatus es un hook introducido como parte de las nuevas características de React para manejar formularios, diseñado para trabajar con la API de <Form /> en aplicaciones React Server Components (RSC). Este hook permite rastrear el estado de los formularios y manejar estados como "enviando" (submitting) o "enviado" (submitted).
1. Qué es useFormStatus? #
useFormStatus te proporciona información sobre el estado actual del formulario:
isSubmitting: Indica si el formulario se está enviando.isValid: Indica si el formulario es válido.
Este hook es útil para:
- Mostrar indicadores de carga (
spinners) durante el envío del formulario. - Deshabilitar elementos del formulario mientras se procesa.
- Mostrar mensajes de éxito o error después de enviar.
2. Requisitos Previos #
- React Server Components (RSC):
useFormStatusestá diseñado para trabajar con formularios manejados por el servidor. - Renderizado en Servidor: Generalmente usado en frameworks como Next.js con soporte para React Server Components.
3. Ejemplo Básico #
Código #
1import React from "react"; 2import { experimental_useFormStatus as useFormStatus } from "react"; 3 4function Formulario() { 5 const { isSubmitting } = useFormStatus(); 6 7 return ( 8 <form action="/api/submit" method="post"> 9 <div> 10 <label> 11 Nombre: 12 <input type="text" name="nombre" /> 13 </label> 14 </div> 15 <div> 16 <label> 17 Correo: 18 <input type="email" name="correo" /> 19 </label> 20 </div> 21 <button type="submit" disabled={isSubmitting}> 22 {isSubmitting ? "Enviando..." : "Enviar"} 23 </button> 24 </form> 25 ); 26} 27 28export default Formulario;
Explicación #
useFormStatus:- Obtiene el estado de envío del formulario (
isSubmitting).
- Obtiene el estado de envío del formulario (
- Botón Deshabilitado:
- Mientras el formulario se está enviando, el botón se deshabilita y muestra "Enviando...".
4. Caso Práctico: Indicador de Carga #
Código #
1import React from "react"; 2import { experimental_useFormStatus as useFormStatus } from "react"; 3 4function FormularioConSpinner() { 5 const { isSubmitting } = useFormStatus(); 6 7 return ( 8 <form action="/api/submit" method="post"> 9 <div> 10 <label> 11 Nombre: 12 <input type="text" name="nombre" required /> 13 </label> 14 </div> 15 <button type="submit"> 16 {isSubmitting ? ( 17 <> 18 <span className="spinner"></span> Enviando... 19 </> 20 ) : ( 21 "Enviar" 22 )} 23 </button> 24 </form> 25 ); 26} 27 28export default FormularioConSpinner;
Estilos para el Spinner #
1.spinner { 2 display: inline-block; 3 width: 16px; 4 height: 16px; 5 border: 2px solid #f3f3f3; 6 border-top: 2px solid #3498db; 7 border-radius: 50%; 8 animation: spin 1s linear infinite; 9} 10 11@keyframes spin { 12 0% { 13 transform: rotate(0deg); 14 } 15 100% { 16 transform: rotate(360deg); 17 } 18}
5. Caso Avanzado: Mensaje de Éxito o Error #
Puedes mostrar mensajes dinámicos basados en el estado del formulario.
Código #
1import React, { useState } from "react"; 2import { experimental_useFormStatus as useFormStatus } from "react"; 3 4function FormularioConMensajes() { 5 const { isSubmitting } = useFormStatus(); 6 const [mensaje, setMensaje] = useState(""); 7 8 const manejarEnvio = async (e) => { 9 e.preventDefault(); 10 setMensaje(""); 11 12 try { 13 const respuesta = await fetch("/api/submit", { 14 method: "POST", 15 body: new FormData(e.target), 16 }); 17 18 if (respuesta.ok) { 19 setMensaje("Formulario enviado con éxito."); 20 } else { 21 setMensaje("Error al enviar el formulario."); 22 } 23 } catch (error) { 24 setMensaje("Hubo un problema. Inténtalo de nuevo."); 25 } 26 }; 27 28 return ( 29 <form onSubmit={manejarEnvio}> 30 <div> 31 <label> 32 Nombre: 33 <input type="text" name="nombre" required /> 34 </label> 35 </div> 36 <button type="submit" disabled={isSubmitting}> 37 {isSubmitting ? "Enviando..." : "Enviar"} 38 </button> 39 {mensaje && <p>{mensaje}</p>} 40 </form> 41 ); 42} 43 44export default FormularioConMensajes;
6. Integración con Next.js #
En aplicaciones Next.js, useFormStatus puede combinarse con rutas de la API (/api) para manejar formularios.
API en Next.js #
1// /pages/api/submit.js 2export default function handler(req, res) { 3 if (req.method === "POST") { 4 const { nombre, correo } = req.body; 5 // Simular éxito o error 6 if (nombre && correo) { 7 res.status(200).json({ message: "Formulario enviado con éxito" }); 8 } else { 9 res.status(400).json({ error: "Faltan datos" }); 10 } 11 } else { 12 res.setHeader("Allow", ["POST"]); 13 res.status(405).end(`Método ${req.method} no permitido`); 14 } 15}
7. Limitaciones de useFormStatus #
-
Solo Compatible con React Server Components:
- Requiere un entorno que soporte React Server Components.
-
Dependencia del Envío:
- Solo puede rastrear formularios que usen la API de formularios del servidor.
-
No Funciona con Todo Tipo de Formularios:
- No se puede usar para manejar formularios controlados (
useState).
- No se puede usar para manejar formularios controlados (
8. Buenas Prácticas #
-
Habilitar Indicadores de Carga:
- Usa
isSubmittingpara deshabilitar botones o mostrar spinners.
- Usa
-
Mensajes Dinámicos:
- Proporciona retroalimentación al usuario después del envío.
-
Validación en el Cliente y Servidor:
- Combina validaciones del lado del cliente con validaciones en el servidor para una experiencia robusta.
Resumen del tema
Conceptos clave #
- Hook de Estado de Formulario (
useFormStatus): disponible enreact-dom(React 19 / Server Actions) para leer el estado del formulario padre más cercano. - Propiedades Retornadas:
pending: booleano que indica si el formulario padre está en pleno proceso de envío asíncrono.data: objetoFormDataque se está transmitiendo.methodyaction: detalles del método HTTP y la Server Action invocada.
- Regla de Ubicación: debe llamarse dentro de un componente hijo anidado dentro de la etiqueta
<form>, no en el mismo componente que declara el<form>. - Casos de Uso: botones de envío inteligentes con spinners y estado
disabled={pending}sin elevar estado manualmente.
Qué debes recordar #
useFormStatus lee el estado de envío (pending, data) del formulario padre desde un componente hijo para gestionar botones y spinners automáticamente.