Saltar al contenido

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

jsx
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

  1. Inicializa el total en cero.

  2. Ejecuta tres actualizaciones funcionales.

  3. Añade un botón que dispare la acción.

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

Dos colas desde 0: tres reemplazos setCount(count + 1) terminan en 1; tres funciones setCount(n => n + 1) encadenan 0, 1, 2 y 3.
CursaloMapa de práctica
Tres llamadas, dos resultados

En 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 ↗
Dos cadenas usuario y direccion: la copia nueva cambia ciudad Madrid por Lima y conserva codigo_postal 28001, mientras la versión anterior permanece intacta.
CursaloMapa de práctica
Copia cada nivel que cambia

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

01 / ELEGIR UNA RUTA

El próximo paso

Aprende IA mientras construyes algo que sí necesitas.

Empieza por el curso inicial o explora el catálogo para encontrar una práctica alineada con tu trabajo.