Lección 10 de 13 · Lectura y práctica
Manejando multiples estados
Organizando el estado Multiples useState function Formulario() { const [nombre, setNombre] = useState(''); const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [errors, setErrors] =.
Del concepto a la práctica
Taller de esta lección
Separar estados ayuda a que cada transición tenga un propósito claro. En un formulario de reserva, los campos pertenecen a los datos del visitante, mientras enviado describe la interfaz. Agrupar los campos relacionados reduce setters repetidos, pero no obliga a mezclar allí el estado visual.
Ejemplo resuelto
El bloque autónomo revisado se encuentra más abajo.
Al cambiar nombre, correo se conserva porque se copia el objeto previo.
Pruébalo
Define dos campos dentro de
form.Actualiza por nombre de campo.
Mantén
enviadoen un estado separado.Comprueba una transición de confirmación.
Comprueba tu resultado
Tras escribir “Ana” y “ana@ejemplo.test”, la cadena debe conservar ambos valores.
Error frecuente: reemplazar todo el objeto con { [name]: value }; corrígelo usando ...prev. No guardes nombreCompleto si puede calcularse a partir de campos existentes.
Formulario conectado y validación local
La versión autónoma siguiente sustituye el fragmento sin inputs ni handler de envío. Colócala en un archivo JSX y móntala desde App.
import {useState} from 'react';
export default function Reserva(){
const [form,setForm]=useState({nombre:'',correo:''});
const [enviado,setEnviado]=useState(false);
const [error,setError]=useState('');
function cambiar(e){
const {name,value}=e.target;
setForm(prev=>({...prev,[name]:value}));
setEnviado(false);setError('');
}
function enviar(e){
e.preventDefault();
const valido=form.nombre.trim()!=='' && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(form.correo.trim());
setEnviado(valido);setError(valido?'':'Revisa nombre y correo');
}
return <form onSubmit={enviar}>
<label>Nombre<input name="nombre" value={form.nombre} onChange={cambiar}/></label>
<label>Correo<input name="correo" value={form.correo} onChange={cambiar}/></label>
<button type="submit">Confirmar</button>
<p>{enviado?'Confirmada':`${form.nombre}|${form.correo}`}</p>
<p role="status">{error}</p>
</form>;
}Ana/ana@ejemplo.test conserva ambos campos y permite Confirmada; espacios/ana@ rechaza y conserva las entradas. El email usa una regla sencilla del laboratorio, no verifica un buzón real. Editar tras confirmar devuelve la vista a pendiente. No hay envío a servidor ni reserva persistida.

Mapa de prácticaNombre y apellido son entradas de estado; el nombre completo se calcula durante render. Evitar otra copia de estado elimina la necesidad de sincronizar tres valores que representan la misma información.
Ver la infografía en tamaño completo ↗
Mapa de prácticaEl evento onChange crea nuevoForm, una copia del objeto con el nombre actualizado, y llama setForm(nuevoForm). La prop value refleja form.nombre; al enviar, trim detecta texto vacío y conserva el campo para corregirlo. Confirmada representa una validación local, no una respuesta de servidor.
Ver la infografía en tamaño completo ↗Organizando el estado
Multiples useState
function Formulario() {
const [nombre, setNombre] = useState('');
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [errors, setErrors] = useState({});
const [isSubmitting, setIsSubmitting] = useState(false);
// Cada estado es independiente
// Util cuando no estan relacionados
}
Estado agrupado
function Formulario() {
// Agrupa estados relacionados
const [form, setForm] = useState({
nombre: '',
email: '',
password: ''
});
const [ui, setUi] = useState({
isSubmitting: false,
errors: {}
});
const handleChange = (e) => {
const { name, value } = e.target;
setForm(prev => ({ ...prev, [name]: value }));
};
}
Cuando separar vs agrupar?
- Separar: Estados que cambian independientemente
- Agrupar: Estados que siempre cambian juntos
Ejemplo practico: Filtros
function ProductList() {
// Estados de filtro (relacionados)
const [filters, setFilters] = useState({
categoria: 'all',
precioMin: 0,
precioMax: 1000,
ordenar: 'nombre'
});
// Estado de datos (independiente)
const [productos, setProductos] = useState([]);
// Estado de UI (independiente)
const [isLoading, setIsLoading] = useState(false);
const updateFilter = (key, value) => {
setFilters(prev => ({ ...prev, [key]: value }));
};
return (
<div>
<select
value={filters.categoria}
onChange={(e) => updateFilter('categoria', e.target.value)}
>
<option value="all">Todas</option>
<option value="tech">Tecnologia</option>
</select>
<input
type="range"
value={filters.precioMax}
onChange={(e) => updateFilter('precioMax', e.target.value)}
/>
</div>
);
}
Levantando el estado (Lifting State)
// Cuando dos componentes necesitan compartir estado,
// muevelo al componente padre mas cercano
function App() {
const [temperatura, setTemperatura] = useState(20);
return (
<div>
<TermometroA temp={temperatura} onCambiar={setTemperatura} />
<TermometroB temp={temperatura} onCambiar={setTemperatura} />
</div>
);
}Sigue con React Fundamentals
Esta lección forma parte de un curso de Cursalo. Revisa su programa y elige entre la compra individual o el acceso a toda la escuela.
Si ya tenías acceso a este curso, entra con tu cuenta: tus derechos y tu progreso se conservan. No necesitas comprarlo de nuevo.