Construir una to-do list con emojis usando Zustand te permite practicar el manejo de estado global en React sin la complejidad de Redux. Aquí conectarás un store previamente creado con un componente funcional en TypeScript, capturarás la entrada del usuario y mapearás palabras a emojis para renderizar la lista.
Esta guía es para quienes ya entienden React básico y quieren ver cómo se integran hooks personalizados, estado local con useState y eventos del teclado en una aplicación real.
¿Cómo conectar el hook useTodoStore al componente?
El primer paso es declarar el componente y traer las acciones del store que creaste previamente. Esto te da acceso al arreglo de todos y a las funciones para agregar y eliminar.
tsx
import { useTodoStore } from './store/useTodoStore';
const TodoList: React.FunctionComponent = () => {
const todos = useTodoStore((state) => state.todos);
const addTodo = useTodoStore((state) => state.addTodo);
const removeTodo = useTodoStore((state) => state.removeTodo);
};
Cada llamada a useTodoStore recibe un selector que retorna solo la porción del estado que necesitas. Esto evita renders innecesarios y mantiene el componente desacoplado [03:15].
¿Qué es un selector en Zustand? Es una función que recibe el estado completo y retorna solo la parte que tu componente necesita, optimizando el rendimiento.
¿Por qué necesitas estado local junto al estado global?
El store guarda la lista persistente, pero el texto que el usuario está escribiendo en el input es temporal. Para eso usas useState.
tsx
const [todoText, setTodoText] = useState('');
Esta variable captura cada pulsación del teclado y se limpia cuando el todo se agrega correctamente. Separar estado local del global es una buena práctica: lo efímero vive en el componente, lo compartido vive en el store.
¿Cómo mapear palabras a emojis con TypeScript?
Para que la palabra eat se transforme en una hamburguesa necesitas un objeto de mapeo tipado. La clave y el valor son ambos string.
tsx
const emojiMap: { [key: string]: string } = {
eat: '🍔',
sleep: '🛏️',
exercise: '🏋️'
};
Luego, en la función que agrega el todo, conviertes el texto a minúsculas con toLowerCase() para que el mapeo funcione sin importar cómo escriba el usuario, y usas trim() para validar que no esté vacío.
tsx
const handleAddTodo = () => {
const mappedText = emojiMap[todoText.toLowerCase()] || todoText;
if (mappedText.trim()) {
addTodo(mappedText);
setTodoText('');
}
};
El operador || actúa como fallback: si la palabra no está en el mapa, se guarda el texto original [06:42].
¿Cómo detectar la tecla Enter en React con TypeScript?
En lugar de un botón, el componente ejecuta la acción cuando el usuario presiona Enter. Esto se logra con el evento onKeyDown y el tipo React.KeyboardEvent.
tsx
const handleKeyDown = (event: React.KeyboardEvent) => {
if (event.key === 'Enter') {
handleAddTodo();
}
};
Tipar el evento es clave en TypeScript porque te da autocompletado y previene errores como acceder a propiedades inexistentes.
¿Qué tipo se usa para eventos de teclado en React? Se usa React.KeyboardEvent, que expone propiedades como key, code y shiftKey con tipado completo.
¿Cómo renderizar la lista y eliminar elementos al hacer clic?
El return del componente arma el HTML con un input controlado y un <ul> que itera sobre los todos. Cada <li> recibe una key única basada en el id y un onClick que dispara removeTodo.
tsx
return (
<div>
<p>Made with Zustand</p>
<h1>Emoji Todo List</h1>
<input
type="text"
value={todoText}
onChange={(e) => setTodoText(e.target.value)}
onKeyDown={handleKeyDown}
placeholder="Add a new todo"
/>
<ul>
{todos.map((todo) => (
<li key={todo.id} onClick={() => removeTodo(todo.id)}>
{todo.text}
</li>
))}
</ul>
</div>
);
El input controlado significa que su valor depende del estado de React, no del DOM. Cada cambio dispara onChange, que actualiza todoText y vuelve a renderizar el componente.
Cómo exportar y montar el componente
Para que la aplicación lo use, agrega export default TodoList al final del archivo y reemplaza el componente App en main.tsx por TodoList. Sin el export default, Vite arrojará un error de importación [10:28].
Qué probar en el navegador
Al escribir eat y presionar Enter aparece una hamburguesa. Lo mismo con sleep y exercise. Al hacer clic sobre cualquier elemento, se elimina de la lista.
Si escribes una palabra que no está en el emojiMap, se renderiza el texto tal cual lo ingresaste, gracias al fallback del operador ||.
¿Con cuál te quedas para tus proyectos: Redux o Zustand? Cuéntame en los comentarios cuál sentiste más cómoda y por qué.