Domina los Formularios en React: Guía Definitiva

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.

Sincronización del Estado con un Campo de Entrada


Veamos un ejemplo básico de un campo de entrada controlado:

jsx
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>
);
}

Paso 1: Inicializar el Estado

Inicializamos el estado con un valor inicial. En este caso, un campo de entrada que almacenará un nombre:

jsx
const [name, setName] = useState("");

Paso 2: Vincular el Campo con el Estado

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:

jsx
<input type="text" value={name} onChange={updateName} />

El manejador updateName se encarga de actualizar el estado con el valor actual del campo:

jsx
function updateName(e) {
setName(e.target.value);
}
  Ventaja de este Enfoque

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.

jsx
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>
);
}

Formularios con Múltiples Campos


Cuando trabajamos con formularios más complejos que tienen múltiples campos, podemos usar un objeto en el estado para almacenarlos:

jsx
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>
);
}
  Explicación del Código

  1. Estado como Objeto: Usamos un único estado formData para manejar múltiples campos del formulario.
  2. Propiedad name: Aseguramos que cada campo tiene un atributo name que corresponde a una clave en el estado.
  3. Función handleChange: Actualizamos dinámicamente el estado con el nombre y el valor del campo.

Validación de Formularios


Podemos agregar validaciones al formulario antes de enviar los datos. Por ejemplo:

jsx
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.