Construir un emoji todo list con Redux Toolkit te enseña a despachar acciones, conectar reducers y manejar estado global en React de forma práctica. Aprenderás a integrar useDispatch, useSelector y el Provider para que cualquier componente lea y modifique el estado compartido.
Cómo conectar el reducer al store de Redux
Antes de tocar los componentes, necesitas que el store reconozca el reducer que vas a usar. En el archivo store.ts importas el todoReducer desde la carpeta features/todos/todoReducer y lo registras dentro de la configuración del store.
Esta conexión es la que permite que el estado global tenga una sección dedicada a los todos. Sin ese registro, ningún componente podría leer ni modificar la lista [00:24].
¿Qué hace configureStore en Redux Toolkit? Crea el store global y registra los reducers que manejan cada porción del estado. Es el punto único desde donde toda la app lee y escribe datos compartidos.
Cómo despachar acciones con useDispatch en React Redux
El componente TodoList.tsx arranca como un functional component tipado. Dentro declaras una constante dispatch igual a useDispatch(), importado desde react-redux. Como Redux Toolkit no instala esta librería por defecto, corres npm install react-redux para tenerla disponible [01:30].
Para que TypeScript entienda el tipo del dispatch, importas AppDispatch desde app/store y se lo asignas: useDispatch<AppDispatch>(). Así aprovechas los tipos que ya creaste en clases anteriores y evitas errores silenciosos.
Luego importas las acciones addTodo y removeTodo desde features/todos/todoActions. Estas son las que vas a disparar desde las funciones del componente.
Cómo crear la función handleAddTodo
La función handleAddTodo ejecuta dispatch(addTodo(texto)) para agregar un nuevo elemento. El texto viene de un estado local creado con useState, llamado todoText, que captura lo que el usuario escribe en el input.
Después de despachar la acción, limpias el estado con setTodoText("") para que el input quede vacío y listo para el siguiente todo [04:10].
Cómo crear la función handleRemoveTodo
Para eliminar usas la misma estructura, pero recibiendo un id numérico como parámetro. Dentro despachas removeTodo(id), que activa el filtrado definido en el reducer y elimina el elemento correspondiente de la lista.
Cómo mapear texto a emojis con un objeto en TypeScript
La idea del proyecto es que el usuario escriba una palabra como eat y la lista muestre un emoji asociado. Para lograrlo creas una constante emojiMap tipada como { [key: string]: string }.
Dentro del objeto defines pares clave-valor:
eat se asocia con el emoji de hamburguesa.
sleep se asocia con el emoji de cama.
exercise se asocia con un emoji de ejercicio.
En handleAddTodo creas la variable mapText que toma emojiMap[todoText.toLowerCase()] || todoText. Con toLowerCase normalizas la entrada para que no importe si el usuario escribe en mayúsculas, y con el operador || garantizas que si la palabra no está mapeada, se muestre el texto original [07:45].
La validación if (mapText.trim()) evita que se agreguen entradas vacías o con solo espacios.
¿Por qué usar toLowerCase() antes de mapear? Porque normaliza la entrada del usuario y hace que Sleep, SLEEP o sleep apunten todos al mismo emoji. Evita duplicar claves en el objeto.
Cómo leer el estado global con useSelector
Para renderizar la lista necesitas leer los todos desde el store. Creas la constante todos igual a useSelector((state: RootState) => state.todos). El tipo RootState también viene de app/store y le da autocompletado y seguridad a la lectura del estado.
Dentro del JSX recorres el array con todos.map((todo) => ...) y por cada elemento renderizas un <li> con key={todo.id}, mostrando todo.text. El onClick de cada item ejecuta handleRemoveTodo(todo.id), lo que dispara la eliminación al hacer clic.
Cómo capturar el Enter en el input
El input tiene tres atributos clave:
value={todoText} para reflejar el estado local.
onChange={(event) => setTodoText(event.target.value)} para actualizar el estado en cada tecla.
onKeyDown={(event) => { if (event.key === "Enter") handleAddTodo() }} para disparar la acción al presionar Enter.
Esta combinación es el patrón estándar para inputs controlados en React conectados a Redux.
Cómo envolver la app con el Provider de React Redux
En main.tsx reemplazas el componente App por TodoList y envuelves todo dentro de <Provider store={store}>. Tanto Provider como store se importan: Provider desde react-redux y store desde app/store [12:50].
Sin ese Provider, ningún hook de Redux funciona porque los componentes no tendrían acceso al store global. Es el puente entre la configuración del store y el árbol de componentes.
Al probar la app en el navegador, escribir eat y presionar Enter agrega el emoji de hamburguesa. Lo mismo con exercise y Sleep (en mayúscula), confirmando que el toLowerCase funciona. Al hacer clic en cualquier elemento, se elimina de la lista.
Cuándo usar Redux y cuándo useReducer
La diferencia es directa: useReducer sirve para estado local complejo dentro de un componente, mientras que Redux maneja estado global compartido entre múltiples componentes. Si varios componentes necesitan leer o modificar los mismos datos, Redux es la opción.
Redux tradicional pide escribir bastante código (acciones, reducers, tipos, providers), pero herramientas como Zustand reducen esa carga y ofrecen una forma más sencilla de manejar estado global.
¿Ya implementaste tu propio todo list con Redux Toolkit? Cuéntame en los comentarios qué emojis agregaste a tu mapa.