Lograr que una aplicación de to-dos en React responda cuando el usuario marca una tarea como completada o la borra es uno de los pasos más satisfactorios del desarrollo. Aquí se construyen las dos funciones clave —completeTodo y deleteTodo— directamente en el componente App.js, se explica cómo respetar la inmutabilidad del estado y se conecta todo con los componentes hijos mediante props.
¿Cómo marcar un to-do como completado en React?
El punto de partida es crear una función llamada completeTodo dentro de App.js [00:08]. Esta función recibe como parámetro el texto del to-do, que actúa como identificador único: cada tarea debe tener un texto diferente para que el sistema funcione correctamente.
Dentro de la función se utiliza el método findIndex [01:05]. Este método recorre el array de to-dos y evalúa, elemento por elemento, cuál cumple la condición todo.text === text. Cuando lo encuentra, devuelve la posición (el index) dentro del array. Hay un detalle importante que menciona el linter de React: las comparaciones deben hacerse con triple igual (===) en lugar de doble igual (==) para evitar coerciones de tipo inesperadas [06:44].
Una vez obtenido el index, no se puede modificar el estado directamente. React necesita recibir un nuevo array para disparar un re-render. Aquí entra en juego el spread operator (...) [03:56]: se crea una copia del array original con const newTodos = [...todos], se modifica la propiedad completed del elemento correspondiente a true, y finalmente se llama a setTodos(newTodos) para actualizar el estado.
js
const completeTodo = (text) => {
const todoIndex = todos.findIndex(todo => todo.text === text);
const newTodos = [...todos];
newTodos[todoIndex].completed = true;
setTodos(newTodos);
};
¿Por qué no se puede editar el estado directamente?
React depende de las funciones setter como setTodos para saber cuándo debe volver a renderizar los componentes [03:30]. Si se muta el array original sin pasar por el setter, React no detecta el cambio y la interfaz no se actualiza. Por eso siempre se clona el array, se hacen los cambios en la copia y se envía esa copia al estado.
¿Cómo se conecta la función con el componente TodoItem?
Desde App.js se pasa una prop llamada onComplete al componente TodoItem [05:15]. Esta prop es una arrow function que llama a completeTodo con el texto del to-do correspondiente:
jsx
<TodoItem onComplete={() => completeTodo(todo.text)} />
Dentro de TodoItem, el evento onClick del botón de check invoca props.onComplete. Al hacer clic, el to-do aparece en verde y con el texto tachado, y el TodoCounter se actualiza automáticamente porque la cantidad de completados cambió [07:15].
¿Cómo eliminar un to-do con el método splice?
La función deleteTodo sigue una lógica muy parecida [08:18]. Recibe el texto, busca el index con findIndex y clona el array. La diferencia está en que, en lugar de cambiar una propiedad, se utiliza el método splice para remover el elemento.
El método splice espera dos argumentos [09:00]: la posición desde donde se empieza a cortar y la cantidad de elementos a eliminar. Se usa la analogía de un pan tajado: se coloca el cuchillo en la tajada indicada por todoIndex y se saca exactamente una tajada.
js
const deleteTodo = (text) => {
const todoIndex = todos.findIndex(todo => todo.text === text);
const newTodos = [...todos];
newTodos.splice(todoIndex, 1);
setTodos(newTodos);
};
Después se pasa la prop onDelete al componente TodoItem de la misma forma que onComplete [10:12]. En el componente hijo, el botón con la X ejecuta props.onDelete al recibir un clic.
¿Qué pasa con la persistencia de datos?
Al probar la aplicación, tanto completar como borrar funcionan perfectamente: el contador se actualiza, los estilos cambian y los elementos desaparecen de la lista [10:50]. Sin embargo, al recargar la página los cambios se pierden, porque el estado solo vive en memoria. La solución se aborda en el módulo de persistencia con localStorage [07:50].
Con estas dos funciones la aplicación ya cubre las operaciones de completar y eliminar. Solo queda implementar la creación de nuevos to-dos para tener el ciclo completo. ¿Ya intentaste construir la función de agregar por tu cuenta antes de ver la siguiente clase?