Construye un Emoji ToDo List en React con TypeScript usando el hook useReducer: organiza el estado, despacha acciones y controla la UI con entradas de texto y clics. Aquí verás cómo integrar dispatch, payload y un mapeo de texto a emojis con un flujo claro y mantenible.
¿Cómo configurar useReducer con estado inicial y reducer?
Al iniciar, se reemplaza el componente por defecto por TodoList y se importa useReducer. Este hook recibe el reducer y el estado inicial. Devuelve el state global y la función dispatch para ejecutar acciones.
- Importar useReducer y preparar el componente funcional.
- Pasar el reducer y el estado inicial al hook.
- Usar state para leer y dispatch para modificar.
import { useReducer, useState } from 'react';
// import { todoReducer, initialState } from './todoReducer';
const TodoList: React.FC = () => {
const [state, dispatch] = useReducer(todoReducer, initialState);
const [todoText, setTodoText] = useState('');
return null; // se completará abajo
};
export default TodoList;
¿Por qué usar useReducer en lugar de useState?
Porque centraliza la lógica en un reducer, facilita acciones de agregar y eliminar, y hace más claro el flujo entre componente, acciones y reducer. Para estados con múltiples transiciones, resulta más simple y escalable que useState.
¿Cómo agregar tareas con mapeo de texto a emojis?
Se usa un estado local con useState para el texto del input. Al agregar, una función transforma el texto a minúsculas con toLowerCase() y consulta un objeto de mapeo. Si no existe, usa el texto del usuario. Luego despacha la acción addTodo con el payload correcto y limpia el campo.
- Estado local controlado para el input.
- Transformación con
toLowerCase() para evitar errores por mayúsculas.
- Fallback al texto del usuario si no hay emoji.
- Despacho de acción
addTodo con el texto mapeado.
// mapa predefinido texto → emoji
const emojiMap: Record<string, string> = {
// 'it': '...', 'sleep': '...', 'exercise': '...'
};
const handleAddTodo = () => {
const lowered = todoText.toLowerCase();
const mappedText = emojiMap[lowered] ?? todoText.trim();
dispatch({ type: 'addTodo', payload: mappedText });
setTodoText('');
};
¿Qué detalles cuidan la calidad de la entrada?
toLowerCase() evita fallos por mayúsculas al mapear.
.trim() reduce espacios innecesarios.
- Limpiar el input mantiene una UX fluida.
¿Cómo detectar enter y renderizar la lista con acciones?
Para capturar el envío al presionar Enter, se crea handleKeyDown con tipo React.KeyboardEvent. En el JSX se arma el input controlado y la lista con map. Cada elemento se elimina con un clic despachando removeTodo con el id.
- Detección de tecla con
onKeyDown y e.key === 'Enter'.
- Input controlado con
value y onChange.
- Renderizado con
state.todos.map y claves únicas.
- Eliminación mediante
dispatch({ type: 'removeTodo', payload: id }).
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === 'Enter') handleAddTodo();
};
return (
<div>
<span>madeWithUseReducer</span>
<h2>emoji todo list</h2>
<input
type="text"
value={todoText}
onChange={(e) => setTodoText(e.target.value)}
onKeyDown={handleKeyDown}
placeholder="add a new todo"
/>
<ul>
{state.todos.map((todo) => (
<li
key={todo.id}
onClick={() => dispatch({ type: 'removeTodo', payload: todo.id })}
>
{todo.text}
</li>
))}
</ul>
</div>
);
¿Qué corrección evitó que no aparecieran los emojis?
Al principio se despachaba el payload con el texto original. Al cambiarlo por el texto mapeado (el resultado del objeto de emojis), los emojis se renderizan correctamente al presionar Enter.
¿Qué habilidades y keywords practicas?
- Configuración de useReducer con reducer y estado inicial.
- Manejo de state global y dispatch de acciones.
- Tipado de eventos con KeyboardEvent en React.
- Mapeo de strings a emojis con
toLowerCase().
- Input controlado con
value y onChange.
- Renderizado con map y claves únicas.
- Acciones
addTodo y removeTodo con payload tipado.
¿Te animas a contarnos qué emojis añadiste y cómo te fue con el flujo de acciones?