Lección 9 de 13 · Lectura y práctica
Actualizando estado correctamente
Patrones de actualizacion de estado Actualizacion basada en valor anterior function Contador() { const [count, setCount] = useState(0); // MAL - puede fallar con multiples clicks rapidos const incrementarMal = () => {.
Del concepto a la práctica
Taller de esta lección
Cuando una actualización depende del valor anterior, la forma funcional expresa esa dependencia sin capturar una versión antigua. Esto es esencial si una acción añade tres unidades de disponibilidad o incrementa tres veces un contador en el mismo evento.
Ejemplo resuelto
import {useState} from 'react';
function Reservas() {
const [total, setTotal] = useState(0);
const añadirTres = () => {
setTotal(prev => prev + 1);
setTotal(prev => prev + 1);
setTotal(prev => prev + 1);
};
return <button onClick={añadirTres}>{total}</button>;
}Partiendo de cero, el resultado esperado tras un clic es tres.
Pruébalo
Inicializa el total en cero.
Ejecuta tres actualizaciones funcionales.
Añade un botón que dispare la acción.
Compara el valor antes y después.
Comprueba tu resultado
La pantalla debe mostrar 3, no 1.
Error frecuente: repetir setTotal(total + 1), que usa la misma captura en las tres llamadas; corrígelo con prev. Para objetos, crea un objeto nuevo con propagación y modifica solo la propiedad necesaria, sin mutar el original.
Una acción, tres actualizaciones
Importa useState y monta Reservas desde App. Con total0, un clic en añadirTres encola tres funciones y la cuenta siguiente es3; un segundo clic da6. Con tres llamadas setTotal(total+1) dentro del mismo handler que capturó0, se encola el valor1 repetido y queda1. La forma funcional expresa el encadenamiento. El original que califica de malo cada clic individual debe matizarse: React normalmente trata eventos intencionados diferentes por separado; un incremento único no falla automáticamente por clics rápidos.
Las funciones actualizadoras deben ser puras. No llames una API, generes IDs aleatorios ni modifiques objetos externos en prev=>...; desarrollo puede repetir comprobaciones de pureza. Para una dirección anidada crea tanto el objeto usuario como su direccion nuevos: setUsuario(prev=>({...prev,direccion:{...prev.direccion,ciudad:'Lima'}})). Conserva codigo:'28001', incluso si empieza por cero en otro fixture, y verifica que el objeto anterior sigue diciendo Madrid. Una copia solo del nivel superior no independiza el objeto anidado. La prueba compara estados anterior/nuevo y sus referencias, además del valor mostrado.

Mapa de prácticaEn un mismo handler, tres asignaciones calculadas con count=0 solicitan el mismo valor 1. Tres actualizadores funcionales reciben el resultado anterior de la cola y producen 3.
Ver la infografía en tamaño completo ↗
Mapa de prácticaAl cambiar una ciudad anidada, se crean nuevos objetos para usuario y dirección. El usuario anterior conserva Madrid y el código postal se copia; una copia solo del nivel superior no separa la dirección compartida.
Ver la infografía en tamaño completo ↗Patrones de actualizacion de estado
Actualizacion basada en valor anterior
function Contador() {
const [count, setCount] = useState(0);
// MAL - puede fallar con multiples clicks rapidos
const incrementarMal = () => {
setCount(count + 1);
};
// BIEN - usa el valor anterior
const incrementarBien = () => {
setCount(prev => prev + 1);
};
// Incrementar 3 veces
const incrementar3 = () => {
setCount(prev => prev + 1);
setCount(prev => prev + 1);
setCount(prev => prev + 1);
};
return (
<button onClick={incrementar3}>
Count: {count}
</button>
);
}
Actualizando objetos
function Formulario() {
const [form, setForm] = useState({
nombre: '',
email: '',
edad: 0
});
// MAL - muta el estado
const handleChangeMal = (e) => {
form.nombre = e.target.value; // NO!
};
// BIEN - crea nuevo objeto
const handleChange = (e) => {
setForm({
...form, // copia propiedades existentes
[e.target.name]: e.target.value // actualiza una
});
};
return (
<form>
<input
name="nombre"
value={form.nombre}
onChange={handleChange}
/>
<input
name="email"
value={form.email}
onChange={handleChange}
/>
</form>
);
}
Actualizando arrays
function ListaTareas() {
const [tareas, setTareas] = useState(['Estudiar', 'Ejercicio']);
// Agregar
const agregar = (tarea) => {
setTareas([...tareas, tarea]);
};
// Eliminar
const eliminar = (index) => {
setTareas(tareas.filter((_, i) => i !== index));
};
// Actualizar uno
const actualizar = (index, nuevoValor) => {
setTareas(tareas.map((t, i) =>
i === index ? nuevoValor : t
));
};
return (
<ul>
{tareas.map((tarea, i) => (
<li key={i}>
{tarea}
<button onClick={() => eliminar(i)}>X</button>
</li>
))}
</ul>
);
}
Estado con objetos anidados
const [user, setUser] = useState({
nombre: 'Maria',
direccion: {
ciudad: 'Madrid',
codigo: '28001'
}
});
// Actualizar propiedad anidada
const cambiarCiudad = (ciudad) => {
setUser({
...user,
direccion: {
...user.direccion,
ciudad: ciudad
}
});
};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.