0Pricing
Frontend Academy · Lección

useReducer para estados complejos

Modele las transiciones de estado con una función reducer, envíe objetos de acción y prefiera useReducer sobre useState cuando la lógica del estado se vuelva compleja.

useReducer para estados complejos es una lección gratuita de Frontend Academy en CoddyKit. Esta es la lección 2 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Frontend Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Frontend Academy incluye 4 lecciones en total.

Cuando useState no es suficiente

Cuando las transiciones de estado implican lógica compleja, varios valores relacionados o condiciones en las que el nuevo estado depende del anterior de maneras no triviales, useReducer es una opción más clara que realizar varias llamadas a useState.

Patrón de función reducer

Un reducer es una función pura: (state, action) => newState. Recibe el estado actual y un objeto de acción, y devuelve el siguiente estado. No realice mutaciones: devuelva siempre un objeto nuevo.

type Action =
  | { type: 'increment' }
  | { type: 'decrement' }
  | { type: 'reset'; payload: number };

function counterReducer(state: number, action: Action): number {
  switch (action.type) {
    case 'increment': return state + 1;
    case 'decrement': return state - 1;
    case 'reset':     return action.payload;
    default: return state;
  }
}

Sintaxis de useReducer

useReducer(reducer, initialState) devuelve el estado actual y una función dispatch. Llame a dispatch con un objeto de acción para desencadenar una transición de estado.

function Counter() {
  const [count, dispatch] = useReducer(counterReducer, 0);

  return (
    <div>
      <p>{count}</p>
      <button onClick={() => dispatch({ type: 'increment' })}>+</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>-</button>
      <button onClick={() => dispatch({ type: 'reset', payload: 0 })}>Reset</button>
    </div>
  );
}

Acciones tipadas: uniones discriminadas

Use tipos de unión discriminada de TypeScript para las acciones y obtenga una comprobación exhaustiva de tipos en el switch del reducer.

type CartAction =
  | { type: 'ADD_ITEM'; item: CartItem }
  | { type: 'REMOVE_ITEM'; id: string }
  | { type: 'SET_QUANTITY'; id: string; qty: number }
  | { type: 'CLEAR' };

Ejemplo de estado complejo: carrito de compras

Un carrito de compras con operaciones para añadir, eliminar y actualizar cantidades es un caso de uso perfecto para useReducer.

interface CartState {
  items: CartItem[];
  total: number;
}

function cartReducer(state: CartState, action: CartAction): CartState {
  switch (action.type) {
    case 'ADD_ITEM': {
      const exists = state.items.find(i => i.id === action.item.id);
      if (exists) {
        const items = state.items.map(i =>
          i.id === action.item.id ? { ...i, qty: i.qty + 1 } : i
        );
        return { ...state, items, total: calcTotal(items) };
      }
      const items = [...state.items, { ...action.item, qty: 1 }];
      return { ...state, items, total: calcTotal(items) };
    }
    case 'CLEAR': return { items: [], total: 0 };
    default: return state;
  }
}

Dispatch es estable

La función dispatch es estable: no cambia entre renderizados. Puede pasarla como prop o usarla como dependencia de useEffect sin provocar nuevas ejecuciones.

Combinar useReducer + useContext

Un patrón potente: un contexto proporciona tanto el estado como dispatch, de modo que cualquier consumidor puede leer el estado o enviar acciones sin pasar props por componentes intermedios.

const CartContext = createContext<{ state: CartState; dispatch: Dispatch<CartAction> } | null>(null);

function CartProvider({ children }: { children: React.ReactNode }) {
  const [state, dispatch] = useReducer(cartReducer, { items: [], total: 0 });
  return <CartContext.Provider value={{ state, dispatch }}>{children}</CartContext.Provider>;
}

useReducer frente a useState

Elija useReducer cuando el estado tenga varios subvalores, el siguiente estado dependa del anterior de formas complejas, haya muchas transiciones con nombres explícitos o quiera probar la lógica del estado por separado del componente.

Probar reducers de forma aislada

Como los reducers son funciones puras, se pueden probar fácilmente sin renderizar ningún componente.

test('increment action increases count', () => {
  expect(counterReducer(0, { type: 'increment' })).toBe(1);
  expect(counterReducer(5, { type: 'increment' })).toBe(6);
});

test('reset action sets count to payload', () => {
  expect(counterReducer(42, { type: 'reset', payload: 0 })).toBe(0);
});

Immer para actualizaciones inmutables

La biblioteca immer permite escribir código que parece mutar el estado, pero produce un estado nuevo e inmutable. Es útil para actualizar objetos anidados complejos en los reducers.

Comprobación rápida

¿Cuál es la firma de la función de un reducer?

Recapitulación: useReducer

(state, action) => newState: función pura y sin mutaciones. useReducer(reducer, initial) devuelve [state, dispatch]. Use tipos de unión discriminada para las acciones y obtener mayor seguridad. dispatch es estable. Es ideal para estados complejos con muchas transiciones. Combínelo con useContext para gestionar el estado global. Pruebe los reducers de forma independiente como funciones puras.

Preguntas frecuentes

¿La lección «useReducer para estados complejos» es gratis?

Sí — el texto completo de «useReducer para estados complejos» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Frontend Academy, actualiza a CoddyKit PRO. El curso de Frontend Academy incluye 4 lecciones en total.

¿Qué aprenderé en «useReducer para estados complejos»?

Modele las transiciones de estado con una función reducer, envíe objetos de acción y prefiera useReducer sobre useState cuando la lógica del estado se vuelva compleja. Practicas Frontend Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar Frontend Academy?

No se requiere experiencia previa. Frontend Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 2 de 4.

¿Cuánto tiempo toma la lección «useReducer para estados complejos»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de Frontend Academy?

Sí. Cada lección de Frontend Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. useContext para el estado global
  2. useReducer para estados complejos
  3. useMemo y useCallback para mejorar el rendimiento
  4. Hooks personalizados: extraer lógica reutilizable
← Volver a Frontend Academy