Los formularios son una parte fundamental de casi cualquier aplicación web. Permiten recoger información del usuario, validar datos y enviarlos a servidores o APIs. En React, el manejo de formularios tiene ciertas particularidades que lo hacen diferente al JavaScript tradicional.

En este tutorial aprenderás cómo funcionan los formularios en React, qué son los componentes controlados y no controlados, cómo manejar inputs y cómo aplicar validaciones.
Cómo funcionan los formularios en React
En HTML tradicional, los formularios gestionan su propio estado internamente. En React, normalmente el estado del formulario se gestiona desde el componente. Esto permite tener mayor control sobre los datos, validarlos fácilmente y reaccionar a cambios en tiempo real.
React permite manejar formularios de dos formas principales:
- Componentes controlados
- Componentes no controlados
Componentes controlados
Un componente controlado es aquel donde React controla el valor del input mediante el estado del componente. Este es el método más utilizado porque ofrece mayor control y flexibilidad.
Ejemplo básico de input controlado
import { useState } from "react";
function Formulario() {
const [nombre, setNombre] = useState("");
return (
<form>
<input
type="text"
value={nombre}
onChange={(e) => setNombre(e.target.value)}
/>
<p>Nombre: {nombre}</p>
</form>
);
}
En este ejemplo:
- El valor del input está vinculado al estado
nombre. - Cada cambio en el input actualiza el estado.
- El componente se renderiza nuevamente mostrando el nuevo valor.
Este patrón garantiza que React tenga siempre el control de los datos.
Manejo de múltiples inputs
Cuando un formulario tiene varios campos, es común almacenar los datos en un solo objeto.
function Formulario() {
const [formData, setFormData] = useState({
nombre: "",
email: ""
});
const handleChange = (e) => {
const { name, value } = e.target;
setFormData({
...formData,
[name]: value
});
};
return (
<form>
<input
name="nombre"
value={formData.nombre}
onChange={handleChange}
placeholder="Nombre"
/>
<input
name="email"
value={formData.email}
onChange={handleChange}
placeholder="Email"
/>
</form>
);
}
Este enfoque permite manejar formularios grandes de forma más organizada.
Envío del formulario
Para manejar el envío del formulario se utiliza el evento onSubmit.
const handleSubmit = (e) => {
e.preventDefault();
console.log(formData);
};
Uso dentro del formulario:
<form onSubmit={handleSubmit}>
El método preventDefault evita que la página se recargue al enviar el formulario.
Componentes no controlados
Los componentes no controlados delegan el manejo del estado al DOM en lugar de a React. Para acceder a sus valores se utiliza useRef.
Ejemplo
import { useRef } from "react";
function Formulario() {
const inputRef = useRef();
const handleSubmit = (e) => {
e.preventDefault();
console.log(inputRef.current.value);
};
return (
<form onSubmit={handleSubmit}>
<input ref={inputRef} />
<button type="submit">Enviar</button>
</form>
);
}
Este método es más simple, pero ofrece menos control sobre los datos.
Cuándo usar componentes controlados o no controlados
Los componentes controlados son recomendables cuando necesitas:
- Validar datos en tiempo real
- Manipular valores dinámicamente
- Sincronizar el formulario con otros elementos
Los componentes no controlados pueden ser útiles cuando:
- El formulario es muy simple
- No necesitas validaciones complejas
- Quieres reducir código
Validación de formularios en React
La validación permite comprobar que los datos introducidos son correctos antes de enviarlos.
Validación básica
const [error, setError] = useState("");
const handleSubmit = (e) => {
e.preventDefault();
if (!formData.email.includes("@")) {
setError("Email inválido");
return;
}
setError("");
};
Mostrar error en la interfaz:
{error && <p>{error}</p>}
Validación en tiempo real
También puedes validar los datos mientras el usuario escribe.
const handleChange = (e) => {
const { name, value } = e.target;
setFormData({
...formData,
[name]: value
});
if (name === "email" && !value.includes("@")) {
setError("Email inválido");
} else {
setError("");
}
};
Manejo de diferentes tipos de inputs
Checkbox
const [activo, setActivo] = useState(false);
<input
type="checkbox"
checked={activo}
onChange={(e) => setActivo(e.target.checked)}
/>
Select
const [pais, setPais] = useState("");
<select value={pais} onChange={(e) => setPais(e.target.value)}>
<option value="">Selecciona un país</option>
<option value="España">España</option>
<option value="México">México</option>
</select>
Radio buttons
const [genero, setGenero] = useState("");
<input
type="radio"
value="hombre"
checked={genero === "hombre"}
onChange={(e) => setGenero(e.target.value)}
/>
Librerías para manejar formularios
Cuando los formularios se vuelven complejos, existen librerías que facilitan su manejo.
React Hook Form
Permite manejar formularios con menos re-renders y mejor rendimiento.
Ventajas:
- Código más limpio
- Mejor rendimiento
- Validaciones sencillas
- Integración con librerías de validación
Formik
Otra librería popular que simplifica el manejo de formularios y validaciones.

Ingeniero en Informática, Investigador, me encanta crear cosas o arreglarlas y darles una nueva vida. Escritor y poeta. Más de 20 APPs publicadas y un libro en Amazon.