El levantamiento de estado es una técnica de React que pone el estado en una localización donde se pueda pasar como props a los componentes.
Lo ideal es poner el estado en el lugar más cercano a todos los componentes que quieren compartir esa información, así todos nuestros componentes tendrán el mismo estado y cuando este cambie sólo re-renderizará lo necesario.
Esto es justamente lo que haremos ahora para hacer funcionar nuestro contador y nuestro buscador, pero debemos tener mucho cuidado al manejar re-renderizados, porque estos pueden causar una mala experiencia de usuario o incluso romper nuestra aplicación.
Contando TODOs
Dentro de nuestro componente App.js primero necesitamos crear el estado de nuestros TODOs, para apartir de ahí poder saber cuántos TODOs existen y cuántos están completados.
importReactfrom'react';import{TodoCounter}from'./TodoCounter';import{TodoSearch}from'./TodoSearch';import{TodoList}from'./TodoList';import{TodoItem}from'./TodoItem';import{CreateTodoButton}from'./CreateTodoButton';// import './App.css';const defaultTodos =[{text:'Cortar cebolla',completed:true},{text:'Tomar el cursso de intro a React',completed:false},{text:'Llorar con la llorona',completed:true},{text:'LALALALAA',completed:false},];functionApp(){// Estado inicial de nuestros TODOsconst[todos, setTodos]=React.useState(defaultTodos);// Cantidad de TODOs completadosconst completedTodos = todos.filter(todo=>!!todo.completed).length;// Cantidad total de TODOsconst totalTodos = todos.length;return(<React.Fragment>{/* Pasamos el estado a nuestro componente */}<TodoCounter total={totalTodos} completed={completedTodos}/><TodoSearch/><TodoList>{searchedTodos.map(todo=>(<TodoItem key={todo.text} text={todo.text} completed={todo.completed}/>))}</TodoList><CreateTodoButton/></React.Fragment>);}exportdefaultApp;
Una vez teniendo estos datos, ya podemos recibir las props en nuestro contador.
importReactfrom'react';import'./TodoCounter.css';// Desestructuramos los props que pasamos al componentefunctionTodoCounter({ total, completed }){return(<h2 className="TodoCounter">Has completado {completed} de {total}TODOs</h2>);}export{TodoCounter};
Buscando TODOs
Para esto haremos algo parecido a lo que hicimos para contar nuestros TODOs, para tener acceso al valor de la búsqueda desde nuestro componente App.js y ahí filtrar nuestros TODOs.
Primero crearemos nuestro estado de búsqueda en App.js, y utilizaremos el método filter de JavaScript para filtrar los TODOs que coincidan con nuestra búsqueda, y también haremos uso de toLowerCase(), para poder filtrar sin importar si las letras son mayúsculas o minúsculas.
importReactfrom'react';import{TodoCounter}from'./TodoCounter';import{TodoSearch}from'./TodoSearch';import{TodoList}from'./TodoList';import{TodoItem}from'./TodoItem';import{CreateTodoButton}from'./CreateTodoButton';// import './App.css';const defaultTodos =[{text:'Cortar cebolla',completed:true},{text:'Tomar el cursso de intro a React',completed:false},{text:'Llorar con la llorona',completed:true},{text:'LALALALAA',completed:false},];functionApp(){const[todos, setTodos]=React.useState(defaultTodos);// El estado de nuestra búsquedaconst[searchValue, setSearchValue]=React.useState('');const completedTodos = todos.filter(todo=>!!todo.completed).length;const totalTodos = todos.length;// Creamos una nueva variable en donde guardaremos las coincidencias con la búsquedalet searchedTodos =[];// Lógica para filtrarif(!searchValue.length>=1){ searchedTodos = todos;}else{ searchedTodos = todos.filter(todo=>{const todoText = todo.text.toLowerCase();const searchText = searchValue.toLowerCase();return todoText.includes(searchText);});}return(<React.Fragment><TodoCounter total={totalTodos} completed={completedTodos}/><TodoSearch searchValue={searchValue} setSearchValue={setSearchValue}/><TodoList>{/* Regresamos solamente los TODOs buscados */}{searchedTodos.map(todo=>(<TodoItem key={todo.text} text={todo.text} completed={todo.completed}/>))}</TodoList><CreateTodoButton/></React.Fragment>);}exportdefaultApp;