Inicio > Cursos > React > useReducer y Estado Complejo
ReactPatrones AvanzadosLección 10 de 21

useReducer y Estado Complejo

useReducer es como un control remoto con botones específicos para tu televisor (el estado). Cada botón (acción) hace algo diferente: ENCENDER, CAMBIAR_CANAL, SUBIR_VOLUMEN. El reducer es la lógica interna del TV que decide qué hacer con cada botón. Con useState tendrías setEncendido, setCanal, setVolumen, y la lógica dispersa en múltiples handlers. Con useReducer tienes dispatch({ type: "CAMBIAR_CANAL", canal: 5 }) y toda la lógica centralizada en un solo lugar predecible.

Usa useReducer cuando: tienes 3 o más estados relacionados que se actualizan juntos, el nuevo estado depende del anterior de formas complejas, o hay muchas operaciones posibles sobre el mismo estado (como un carrito de compras con agregar, quitar, aumentar cantidad, vaciar). El reducer es una función pura: misma entrada → misma salida, sin efectos secundarios. Esto lo hace muy fácil de testear de forma aislada con expect(reducer(estado, accion)).toEqual(estadoEsperado).

import { useReducer } from "react";

// Reducer - función pura que calcula el nuevo estado
function carritoReducer(estado, accion) {
  switch (accion.type) {
    case "AGREGAR":
      const existente = estado.items.find(i => i.id === accion.producto.id);
      if (existente) {
        return {
          ...estado,
          items: estado.items.map(i =>
            i.id === accion.producto.id
              ? { ...i, cantidad: i.cantidad + 1 }
              : i
          )
        };
      }
      return {
        ...estado,
        items: [...estado.items, { ...accion.producto, cantidad: 1 }]
      };

    case "ELIMINAR":
      return {
        ...estado,
        items: estado.items.filter(i => i.id !== accion.id)
      };

    case "LIMPIAR":
      return { items: [], total: 0 };

    default:
      return estado;
  }
}

const estadoInicial = { items: [], total: 0 };

function Carrito() {
  const [estado, dispatch] = useReducer(carritoReducer, estadoInicial);

  const agregar = (producto) =>
    dispatch({ type: "AGREGAR", producto });

  const eliminar = (id) =>
    dispatch({ type: "ELIMINAR", id });

  const total = estado.items.reduce(
    (acc, i) => acc + i.precio * i.cantidad, 0
  );

  return (
    <div>
      <button onClick={() => agregar({ id: 1, nombre: "Laptop", precio: 999 })}>
        + Laptop
      </button>
      <p>Total: ${total.toFixed(2)}</p>
      <ul>
        {estado.items.map(i => (
          <li key={i.id}>
            {i.nombre} x{i.cantidad}
            <button onClick={() => eliminar(i.id)}>x</button>
          </li>
        ))}
      </ul>
      <button onClick={() => dispatch({ type: "LIMPIAR" })}>Vaciar</button>
    </div>
  );
}
Consejo🏗️ Usa useReducer cuando: el estado tiene múltiples sub-valores, el nuevo estado depende del anterior, o hay muchas acciones relacionadas.
← Formularios y ValidaciónProyecto: App de Películas →

Practica esta lección

Resuelve los ejercicios del curso de React en la app, gratis y con corrección automática.

Empezar a practicar