Trabajar con formularios en React implica sincronizar los valores de los campos de entrada con el estado del componente. Aunque puede requerir un poco más de código en comparación con otros frameworks, esta técnica está alineada con la filosofía de React: mantener todos los cambios al estado de forma explícita.
Veamos un ejemplo básico de un campo de entrada controlado:
import { useState } from 'react';
function App() {
const [name, setName] = useState("");
function updateName(e) {
setName(e.target.value);
}
return (
<div>
<input type="text" value={name} onChange={updateName} />
</div>
);
} Inicializamos el estado con un valor inicial. En este caso, un campo de entrada que almacenará un nombre:
const [name, setName] = useState(""); El valor del campo se sincroniza con el estado usando la propiedad value, y cualquier cambio en el campo dispara el evento onChange para actualizar el estado:
<input type="text" value={name} onChange={updateName} /> El manejador updateName se encarga de actualizar el estado con el valor actual del campo:
function updateName(e) {
setName(e.target.value);
} Podemos acceder fácilmente al valor del estado desde cualquier parte del componente.
En este caso, el botón utiliza el estado name para mostrar una alerta, sin necesidad de interactuar directamente con el DOM.
function App() {
const [name, setName] = useState("");
function updateName(e) {
setName(e.target.value);
}
function saluda() {
alert(`Hola ${name}!`);
}
return (
<div>
<input type="text" value={name} onChange={updateName} />
<button onClick={saluda}>Saluda</button>
</div>
);
} Cuando trabajamos con formularios más complejos que tienen múltiples campos, podemos usar un objeto en el estado para almacenarlos:
import { useState } from 'react';
function App() {
const [formData, setFormData] = useState({
name: "",
email: "",
});
function handleChange(e) {
const { name, value } = e.target;
setFormData({
...formData,
[name]: value,
});
}
function handleSubmit(e) {
e.preventDefault();
alert(`Nombre: ${formData.name}, Email: ${formData.email}`);
}
return (
<form onSubmit={handleSubmit}>
<div>
<label>
Nombre:
<input
type="text"
name="name"
value={formData.name}
onChange={handleChange}
/>
</label>
</div>
<div>
<label>
Email:
<input
type="email"
name="email"
value={formData.email}
onChange={handleChange}
/>
</label>
</div>
<button type="submit">Enviar</button>
</form>
);
} formData para manejar múltiples campos del formulario.name: Aseguramos que cada campo tiene un atributo name que corresponde a una clave en el estado.handleChange: Actualizamos dinámicamente el estado con el nombre y el valor del campo.Podemos agregar validaciones al formulario antes de enviar los datos. Por ejemplo:
function App() {
const [formData, setFormData] = useState({
name: "",
email: "",
});
const [errors, setErrors] = useState({});
function validate() {
const newErrors = {};
if (!formData.name) newErrors.name = "El nombre es obligatorio.";
if (!formData.email) newErrors.email = "El email es obligatorio.";
setErrors(newErrors);
return Object.keys(newErrors).length === 0;
}
function handleSubmit(e) {
e.preventDefault();
if (validate()) {
alert("Formulario enviado con éxito");
}
}
function handleChange(e) {
const { name, value } = e.target;
setFormData({
...formData,
[name]: value,
});
}
return (
<form onSubmit={handleSubmit}>
<div>
<label>
Nombre:
<input
type="text"
name="name"
value={formData.name}
onChange={handleChange}
/>
</label>
{errors.name && <p style={{ color: "red" }}>{errors.name}</p>}
</div>
<div>
<label>
Email:
<input
type="email"
name="email"
value={formData.email}
onChange={handleChange}
/>
</label>
{errors.email && <p style={{ color: "red" }}>{errors.email}</p>}
</div>
<button type="submit">Enviar</button>
</form>
); Con este enfoque, aseguramos que el formulario sea válido antes de enviar los datos.