useReducer con TypeScript: crear reducer tipado

Clase 16 de 31Curso de React Avanzado

Contenido del curso

Patrones de renderizado y composición

Manejo del estado en React

Resumen

Construir la lógica que controla el estado de una aplicación es una de las tareas más importantes cuando trabajas con useReducer en React. Aquí se aborda paso a paso cómo crear la función reducer que permite agregar y eliminar elementos de un emoji to do list, incluyendo el tipado con TypeScript y un mapeo de emojis para enriquecer la experiencia visual.

¿Qué es un reducer y cómo se estructura su función?

Un reducer es una función pura que recibe el estado actual y una acción, y devuelve un nuevo estado. En este caso, la función se llama TodoReducer y utiliza un switch case para determinar qué operación ejecutar según el tipo de acción que llega [0:47].

La firma de la función recibe dos parámetros con sus tipos ya definidos previamente:

  • state: de tipo State, que contiene el array todos con los elementos existentes.
  • action: de tipo Action, que incluye un type (agregar o eliminar) y un payload (el dato que acompaña la acción).

El switch case evalúa action.type y ejecuta el caso correspondiente. Si ningún caso coincide, el default retorna el estado sin modificaciones [5:25].

¿Cómo funciona el caso de agregar un elemento?

Cuando el tipo de acción es addTodo, el reducer debe conservar todo lo que ya existe en el estado y añadir un nuevo elemento [1:44]. Esto se logra con la técnica de desestructuración (spread operator):

typescript case 'addTodo': { const newTodo: Todo = { id: state.todos.length + 1, text: action.payload }; return { todos: [...state.todos, newTodo] }; }

  • Se crea una constante newTodo de tipo Todo con un id generado dinámicamente a partir de la cantidad de elementos actuales más uno [3:30].
  • El texto proviene de action.payload, que es el valor capturado desde el input del componente [3:05].
  • El return combina los todos anteriores (...state.todos) con el nuevo elemento, sin borrar nada de lo existente.

¿Cómo se implementa la eliminación con filter?

Para el caso removeTodo, se utiliza el método filter sobre el array de todos. La idea es retornar únicamente los elementos cuyo id sea diferente al payload que llega en la acción [4:36]:

typescript case 'removeTodo': return { todos: state.todos.filter(todo => todo.id !== action.payload) };

  • filter recorre cada elemento y lo mantiene solo si su id no coincide con el que se quiere eliminar.
  • El componente despacha una acción con el id del elemento a remover como payload, y el reducer se encarga del resto.

¿Qué es el emoji map y por qué necesita tipado?

Después de definir el reducer, se crea un objeto llamado emojiMap que asocia palabras clave con emojis correspondientes [5:55]. Por ejemplo, la palabra eat se vincula con 🍔 y exercise con un emoji de actividad física.

Este mapeo permite que, al ingresar texto en el input, la aplicación reconozca la palabra y muestre su emoji equivalente. El tipado en TypeScript se define así [6:42]:

typescript const emojiMap: { [key: string]: string } = { eat: '🍔', exercise: '🏋️' };

  • La key es de tipo string porque no se conoce de antemano qué palabras ingresará el usuario.
  • El valor también es string porque los emojis se representan como cadenas de texto.

¿Por qué usar switch case en lugar de condicionales simples?

El switch case ofrece una estructura más limpia y escalable cuando existen múltiples tipos de acción [0:55]. Cada case encapsula su lógica de forma independiente, y el default actúa como red de seguridad para retornar el estado intacto ante acciones no reconocidas.

Esta separación clara entre agregar, eliminar y el caso por defecto hace que el código sea más legible y fácil de mantener conforme crezca la aplicación.

Con el reducer y el emoji map listos, solo resta construir el componente que despache las acciones y conecte todo con useReducer para ver el resultado en pantalla. ¿Qué emojis agregarías a tu propio mapeo?