Contenido del curso

Herramientas avanzadas: escalabilidad, organización y persistencia

Filtrar TODOs con estados derivados en React

Resumen

Construir un buscador funcional en React requiere combinar estados, props y estados derivados para filtrar información en tiempo real. Aquí aprenderás a implementar un filtro de búsqueda dentro de una aplicación de TODOs, manejando coincidencias entre mayúsculas y minúsculas y conectando varios componentes de forma reactiva.

Esta guía te muestra paso a paso cómo derivar un nuevo array a partir del estado original, cómo usar los métodos filter e includes, y cómo refactorizar tu código para que sea más legible y declarativo.

¿Cómo funciona un estado derivado para buscar TODOs?

Un estado derivado es un valor que se calcula a partir de otro estado existente. En lugar de guardar la lista filtrada como un estado independiente, la generas cada vez que cambia el estado original.

En este caso parto de dos estados que ya existen en el componente: la lista completa de TODOs y el searchValue que el usuario escribe en el buscador. A partir de ellos creo searchedTodos, que filtra la lista cada vez que el input cambia.

jsx const searchedTodos = todos.filter((todo) => { return todo.text.includes(searchValue); });

El método filter recorre cada elemento del array y devuelve uno nuevo solo con los que pasen la validación. La validación aquí usa includes, un método de los strings que pregunta si un texto contiene a otro en cualquier parte. [02:30]

¿Qué hace el método filter en JavaScript? Recorre un array y devuelve uno nuevo con los elementos que cumplan una condición que tú defines dentro de una función. Si retornas true, el elemento entra; si retornas false, se descarta.

¿Por qué mi buscador no muestra resultados?

Un error muy común cuando empiezas con arrow functions y llaves es olvidar el return. Si tu función filter usa llaves {} pero no retorna nada, el resultado siempre será undefined, que se interpreta como falso, y el array filtrado quedará vacío.

Tienes dos formas de resolverlo:

  • Agregar explícitamente la palabra return antes de la validación.
  • Reemplazar las llaves por paréntesis () para que la arrow function retorne implícitamente.

Ambas opciones funcionan igual. Lo importante es entender que filter necesita un valor booleano por cada iteración para decidir si el elemento se queda o no. [05:50]

¿Dónde renderizo el estado derivado?

El componente TodoList ya no debe renderizar los TODOs por defecto ni el array original sin filtrar. Debe renderizar searchedTodos, que es la versión filtrada y reactiva de tu lista.

Esto significa que cuando el usuario escribe en el buscador, el estado searchValue cambia, lo que dispara un nuevo cálculo de searchedTodos, y la lista visible se actualiza automáticamente. Toda la cadena reactiva fluye sola.

¿Cómo hago un buscador insensible a mayúsculas y minúsculas?

El método includes es estricto: si buscas "la" en minúsculas, no encontrará "LALALA" en mayúsculas. Para muchos buscadores eso es un problema, porque el usuario espera encontrar coincidencias sin importar cómo escribió.

La solución es normalizar ambos textos a minúsculas antes de comparar, usando el método toLowerCase:

jsx const searchedTodos = todos.filter((todo) => { const todoText = todo.text.toLowerCase(); const searchText = searchValue.toLowerCase(); return todoText.includes(searchText); });

Esta transformación solo ocurre dentro de la validación. El usuario sigue viendo los textos originales con sus mayúsculas y minúsculas intactas. [09:15]

¿Qué hace toLowerCase en JavaScript? Convierte un string completo a minúsculas. Es útil para comparaciones donde no quieres que la diferencia entre mayúsculas y minúsculas afecte el resultado.

¿Por qué conviene separar la lógica en variables?

Escribir toda la validación en una sola línea funciona, pero perjudica la legibilidad. Separar todoText y searchText en variables independientes hace que el código sea más declarativo y fácil de leer cuando vuelvas a él semanas después.

El JavaScript moderno permite encadenar muchos métodos, pero declarar variables intermedias con nombres claros es una buena práctica que tu yo del futuro va a agradecer.

¿Qué herramientas de React combinas en este buscador?

Este ejercicio integra varios conceptos que ya viste en clases anteriores y los conecta en una sola funcionalidad real:

  • Estado local con useState para guardar la lista de TODOs y el valor del buscador.
  • Estados derivados que se recalculan cada render a partir de otros estados.
  • Comunicación entre componentes pasando estados y actualizadores como props desde el componente padre.
  • Métodos de arrays y strings como filter e includes para transformar datos sin mutarlos.

La aplicación se siente viva porque cada interacción del usuario, por pequeña que sea, dispara una cadena reactiva que actualiza varios componentes a la vez. [11:20]

¿Cuál es el siguiente reto?

El reto es usar el actualizador setTodos para completar o eliminar TODOs de forma independiente. Necesitas pasar ese actualizador a cada TodoItem y modificar el estado original cuando el usuario haga clic en el botón de completar o eliminar.

Ese cambio debe propagarse al TodoCounter, al TodoSearch y a la TodoList automáticamente, gracias a la reactividad que ya construiste. Inténtalo, rompe todo lo que puedas y cuéntame en los comentarios qué resultados locos te salieron.