Aún no tienes acceso a esta clase

Crea una cuenta y continúa viendo este curso

Contando y buscando TODOs

10/23
Recursos

Aportes 81

Preguntas 12

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad? Crea una cuenta o inicia sesión.

💚 Like si quieres un Curso de Optimización, Rendimiento y Debugging en React.js para profundizar muchísimo más en cómo funcionan los renders y re-renders con React.

Con !, es es negativo
Con !!, es positivo porque niegas al que esta negando y termina siendo positivo

En realidad no necesita el doble !, ya que colocando solo todo.completed filtrará a los que sean true, colocando !! es como colocar !!! ya que todos se eliminan

Juan, sería genial que hicieras los mismo que anda haciendo Jonathan Alvarez con los cursos de Next.js.

Es decir toda una familia de cursos de React para poder aprender todo lo que sea posible, y ojalá que fueras tu el que lo hiciera, tenes mucho talento, crack.

Por finnn, gracias a Juan supe de una manera clara como hacer un buscador sencillo y sin tanta complicación. Que clase maestra. Aquí dejo mi ejemplo puesto en práctica. https://apebogota.com/#empleo

BRUTAL esta clase, me encantó pero, hay que ver un par de veces para absorber todo lo nuevo que se da. Excelente realmente.

Hola 😀

comparto una manera para el filtro

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

componente

<TodoList>
        {filterTodos.map((item, i) => (
          <TodoItem key={i} {...item} />
        ))}
 </TodoList>


Probaron con 4 o más signos de exclamación

const completedTodos = todos.filter((todo) => !!!!todo.completed).length;

PD:

1.- Niega, 2. Niega el anterior, 3. Niega el anterior y así…

Soy tan distraído que me aventé media hora viendo videos de la llorona en YouTube mientras veía la clase.

8.-Contando y buscando TODOs

Combinando el estado con las props podremos enviar desde el componente padre la información del estado y como actualizarlo a todos nuestros componentes. De esta manera los componentes hijos le comunicaran al padre que debe actualizar el estado cuando sea necesario y cuando esto suceda, el padre comunicara el cambio a los demás hijos así toda la app podrá reaccionar a las interacciones de los usuarios.

Cada vez que se cambia el estado se hace render (re-render) con la nueva info, pero como se llama a varios componentes no solo será un re-render sino varios. Hay que tener mucho cuidado con eso.

Veré esta clase todas las veces que sean necesarias hasta entenderla. La explicación es buena, pero por alguna razón no logro asimilar el algoritmo.

Yo filtré los Todos de la siguiente manera:

const todosFiltered = todos.filter(todo => todo.text.toLowerCase().includes(searchValue.toLowerCase()));

Queda mucho más compacto y no es necesario hacer la validación inicial del largo puesto que include si le pasas una cadena vacía te muestra todos.

Digo yo que si el contrario del contrario de verdadero es verdadero, podemos dejarlo como todo.completed en lugar de !!todo.completed 😄

Juan es un excelente Tutor. La lógica de React resulta super sencilla con su explicación.

Como solucion al segundo reto antes de pasar a la siguiente clase esta es mi solucion para actualizar el estado de un todo y como eliminaria un todo de la lista.

  1. Paso al componente TodoItem metiante la props el estado de todos y setTodos
  1. Luego desde el componente TodoItem, al hacer click sobre los iconos de accion y gracias a las funciones creadas en clases anteriores para marcar completado un todo use el metodo map de los array y luego actualice el estado de los todos con el metodo setTodos() el todo y para eliminar use el metodo filter y de igual manera el resultado lo envie a setTodos()

Dios mio, lo logré que felicidad siento en este momento 😭

const [completedTodo, setCompletedTodo] = React.useState(props.completed)

    const onComplete = () => {
        setCompletedTodo(!completedTodo);
    }

// El elemento quedaría así 

<span 
            onClick={onComplete} 
            className={`Icon Icon-check ${completedTodo && 'Icon-check--active'}`}
            >
                √
            </span>

que fascinante esta clase y lo bien que enseña Juan!

Con este Plugin pueden usar comandos para crear el template automáticamente del state
solo colocando:

us /// Enter


También ue para crear un useEffect 😄

Importante: La version de Yoelvis M, es la unica que he visto que hace esto

Quiero decir que dure dos hrs trabado porque me decia error, y en la declarion de

function TodoSearch([searchValue, setSearchValue]) { 
...

Use corchetes ( '[ ’ ‘]’ ) en lugar de llaves ( ‘{’ ‘}’ ) cuidado con tales typos y hagan uso de git diff

Aquí el reto del ejercicio 🥳

Hice una pequeña función para que cuente los todos respecto a su estado mediante reduce, espero les sirva 😃

const todosByState = todos.reduce((prev,curr) => {
    if (curr.completed) prev.completed += 1
    else prev.incomplete += 1

    return prev;

  }, {completed: 0, incomplete: 0});

Hola Amigos como complemento se puede agregar un metodo para limpiar el input de busqueda al teclear ‘ESC’ de todos de la siguiente manera:

function TodoSearch({ searchValue, setSearchValue }) {
  const onSearchValueChange = (event) => {
    setSearchValue(event.target.value);
  };

  const handleKeyDown = (event) => {
    event.keyCode === 27 && setSearchValue("");
  };

  return [
    <input
      className="TodoSearch"
      placeholder="Cebolla"
      value={searchValue}
      onChange={onSearchValueChange}
      onKeyDown={handleKeyDown}
    />,
    <p>{searchValue}</p>,
  ];
}```

Para filtrar la busqueda use esto

  searchedTodos = !searchValue.length?todos:todos.filter(todo => todo.text.toLowerCase().includes(searchValue.toLowerCase()));

My filter solution, I hope it will be useful to you

if (!searchValue.length >= 1) {
    filteredTodos = todos;
  } else {
    filteredTodos = todos.filter((todo) => {
      return todo.text.toLowerCase().match(searchValue.toLowerCase());
    })
  }

De los mismos creadores de Misa de media noche, en este verano, llega, Llorar con la llorona!. Sólo en React.

También se podía hacer con el :

if (!searchValue)

Saber como React maneja los estados hace que ame más Svelte 🧡.
Igualmente se ve interesante la librería, veremos si los de Facebook crean el compilador para React para efectivamente ser reactivo.

esto es oro puro

Me encantaron los retos de esta clase :3

.
El primero no lo comparto porque veo que todos usamos la misma logica, enhorabuena. 😉

.
El segundo me sirvio mucho para comprender mejor como funciona el estado:

yo lo simplifique todo en una asola linea:

const filteredTodos = defaultTodos.filter((todo) => todo.text.toLowerCase().includes(search.toLowerCase()));

Con respecto al reto del final, yo crearia un estado con useState con la opcion completed y setCompleted, luego se las pasaria al componente item como props y desde las props ya crearia una funcion dentro del todoItem que cambie el estado con setCompleted(!completed)

Comparto un recurso para entender un poco mejor la información sobre useState =

Solución al reto:

const todosFilter = todos.filter(todo => todo.text.toLowerCase().includes(searchValue.toLowerCase()));

.
y remplazar aquí:

<TodoList>
{
   todosFilter.map(todo => (
      <TodoItem 
         key={todo.text} 
         text={todo.text} 
         completed={todo.completed} 
      />
   ))
}
</TodoList>

.
Resultado:

Les comparto un poco de lo que he investigado, me costó un poco entender el tema asi que espero les despeje unas dudas

Uso de información en React.

Normalmente cuando creamos una aplicación sin React estamos acostumbrados a usar eventListeners, desde un archivo JavaScript, y en ocasiones pasar la función en HTML, utilizando sus atributos de eventos ( onclick=“funcionX()” ) en React la forma de trabajar es similar a lo último pero debemos tomar en cuenta algunas cosas, primero la información va de padres a hijos, los hijos no saben que tienen padre, pero si saben que les llega información, debido a esto debemos manejar la lógica de sus eventos en un elemento padre, por lo que a los hijos solos les llegará la función por medio de las props.

function App() {
 
  const searchValue = (event) => {
    console.log(event);
  };
 
  return (
    <div className="App">
      <div className="contenedor-principal">
          <h1>ToDo list</h1>
          <div className="contenedor-lista-tareas">
            <TodoCounter />
             <TodoSearch searchValue={searchValue}/>
            <TodoList>
              {
                todos.map(todo => 
                  <TodoItem
                    text={todo.text}
                    completed={todo.completed}
                    key={todo.id}
                    id={todo.id} />
                )
              }
            </TodoList>
            <CreateTodoButton /> 
          </div>
      </div>
    </div>
  );
}

En este ejemplo el componente “<TodoSearch />” esta recibiendo una función en una prop, llamada “searchValue”, por lo que ahora sabe el valor que tendrá esa prop. Entonces dentro del componente:

const TodoSearch = ({searchValue}) => {
  
  return (
    <label htmlFor="name">
      <input type="text" 
             placeholder='Busca una tarea...' 
             id="name"
             onChange={searchValue} />
    </label>
  );
}

serchValue será la función que se ejecute en el evento “onchange”, aquí podemos notar varias cosas:

  • Es posible mandar funciones a elementos hijos, estos no saben de donde provino dicha función pero saben que tienen que ejecutar.

  • Tendremos que trabajar en un elemento padre si es necesario trabajar información que solo tenemos disponible en otro archivo, por lo general la trabajamos en archivo que contiene la App completa pues quien tiene conocimiento de los componentes que la forman, no conoce los hijos de otros componentes pero si los props que tienen dichos componentes.

const searchResult = searchValue.length === 0 ? todos :
  todos.filter(item => item.text.toLowerCase().includes(searchValue.toLowerCase()))


buscando y completando los todos

comparando todos

Gracias Juan comprendí de una manera muy practica de poder hacer algo que me había complicado antes.

Admito que fue una buena clase.

Así resolví el reto, asegurandome de que los string fueran minusculas y si está vacio devuelve los todos.


  const [filter, setFilter] = useState('')
  const [todos, setTodos] = useState(defaultTodos)

const filterTodos = () => {
    return todos.filter(el => el.text.toLocaleLowerCase().includes(filter.toLocaleLowerCase())) || todos
  }

para el segundo reto utilicé un map

export default function TodoItem ({ text, completed, todos, setTodos }) {
  const handlerClick = () => {
    const newList = todos.map(el => {
      if (!(el.text === text)) {
        return el
      }
      el.completed = !el.completed
      return el
    })
    setTodos(newList)
  }

  return (
    <li className='Todo-Item'>
      <span
        onClick={handlerClick}
        className={`Icon Check ${completed && 'Check--active'}`}
      ></span>
      <p className={`Todo-text ${completed && 'Todo-active'}`}>{text}</p>
      <span className='Icon Close'>X</span>
    </li>
  )
};
import React from "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: "ir al curso de react", completed: false},
  {text: "picar cebolla", completed: true},
  {text: "lalalal", completed: false}
]

function App() {

  const [todos, updateTodo] = React.useState(defaultTodos)
  const [searchValue, setSearchValue] = React.useState('')

  const completedTodo = todos.filter(todo=>todo.completed).length
  const totalTodos = todos.length

  let searchedTodo = []

  if (!searchValue.length >=1){
    searchedTodo = todos
  }else{
    searchedTodo = todos.filter(todo=>{
      const todoText = todo.text.toLowerCase()
      const searchedText = searchValue.toLowerCase()
      return todoText.includes(searchedText)
    })
  }

  return (
  <React.Fragment>
      <TodoCounter
        completed={completedTodo}
        total = {totalTodos}
      />
      <TodoSearch
        searchValue={searchValue}
        setSearchValue={setSearchValue}
      />      
      <TodoList>
        {searchedTodo.map(todo =>(
          <TodoItem 
          key={todo.text} 
          text={todo.text}
          completed={todo.completed}
          />
        ))}
      </TodoList>
      <CreateTodoButton/>
  </React.Fragment>
  );
}

export default App;

Me encanta la energia del profe ❤️

Mi filtrado es el siguiente:

  const filtro = todos.filter(ele => ele.text.toLowerCase().includes(searchValue.toLowerCase()))

y ya está, funciona perfectamente, si no escribes nada se muestran todos los TODOs, ahora solo faltaría enviar la constante filtro al componente TodoList para que muestre los TODOs que ha almacenado el filtro

Hice el reto de filtrado de la siguiente manera:

  const filterTodos = todos.filter(todo => todo.text.includes(searchValue))

<TodoList>
        {filterTodos.map(todo => (
          <TodoItem
            key={todo.text}
            text={todo.text}
            completed={todo.completed}
            />
        ))}

Haciendo una lista filtrada según el searchValue y después pasando esa lista para renderizar

Excelente explicación super fácil de entender

Imaginate hacer esto en javascript vainilla 💀💀

Una forma más fácil de filtrar las tareas es esta… simplemente definiendo la variable tasks de tipo let, para poder cambiar su valor con respecto a la búsqueda que el usuario coloque.

let [tasks, setTasks] = React.useState(defaultTasks)
// filtro
tasks = tasks.filter(t => t.text.toUpperCase().includes(searchValue.toUpperCase()))
<TodoList>
  {todos.filter(todo => todo.text.toLowerCase().includes(searchValue.toLowerCase())).map(filteredSearch => (
    <TodoItem
      key={filteredSearch.text}
      text={filteredSearch.text}
      completed={filteredSearch.completed}
    />
  ))}
</TodoList>

Cabe resaltar que la forma en que viajan los datos es que lo componentes anidados desencadenan eventos, que cuando son recibidos por el componente padre, este hace las veces de orquestador, enviando el cambio a otro componente que lo necesite.

// App.tsx

type todoType = {
  text: string;
  completed: boolean;
};

const defaultTodos: todoType[] = [
  { text: "Crear smart app", completed: true },
  { text: "Lavar loza Lorem ipsum in dolor sit amet", completed: true },
  { text: "Mirar las plantas", completed: true },
  { text: "Mirar las plantas Lorem ipsum in dolor sit amet", completed: false },
];

function App() {
  const [todos, setTodos] = useState<todoType[]>(defaultTodos);
  const [searchValue, setSearchValue] = useState<string>('');
  
  const completedTodos = todos.filter((todo) => todo.completed === true).length;
  const totalTodos = todos.length;

  let searchedTodos = []; 
  if (!(searchValue.length >= 1)) {
    searchedTodos = todos;
  } else {
    searchedTodos = todos.filter((todo) => {
      const todoText = todo.text.toLowerCase();
      const searchText = searchValue.toLowerCase();
      return todoText.includes(searchText);
    })
  }

  return (
    <div className="App max-w-lg mx-auto flex flex-col justify-center">
      <TodoCounter completed={completedTodos} total={totalTodos}/>
      <TodoSearch searchValue={searchValue} setSearchValue={setSearchValue} />
      <TodoList>
        {searchedTodos.map((todo) => (
          <TodoItem
            key={todo.text}
            text={todo.text}
            completed={todo.completed}
          />
        ))}
      </TodoList>
      <CreateTodoButton />
    </div>
  );
}

.

// todo-counter.tsx
type completedTypes = {
  completed: number;
  total: number;
};

const TodoCounter = ({ completed, total }: completedTypes) => {
  return (
    <div className="p-6">
      <h2 className="text-3xl font-bold">Tareas</h2>
      <p className="text-xl text-center">Has completado <b>{`${completed} de ${total}`}</b> tareas</p>
    </div>
  );
};

.

// todo-search.tsx
const TodoSearch = ({ searchValue, setSearchValue })=> {
  const onSearchEvent = (event: any) => setSearchValue(event.target.value)

  return (<>
    <div className="p-6 flex justify-center">
      <input
        type="text"
        className="border p-2 border-slate-300 hover:border-b-indigo-900 focus:outline-none"
        placeholder='Buscar o crear nueva tarea'
        onChange={onSearchEvent}
      />
    </div>
    <span className="">{`Estas buscando: ${searchValue}`}</span>
  </>);
};

Comparto como quedo

import React from 'react';
import { TodoCounter} from './TodoCounter/TodoCounter';
import { TodoSearch } from './TodoSearch/TodoSearch';
import { CreateTodoButton } from './CreateTodoButton/CreateTodoButton';
import { TodoList } from './TodoList/TodoList';
import { TodoItem } from './TodoItem/TodoItem';


const todosList = [
{
  text: 'Learn React',
  completed: false
},
{
  text: 'Practice React',
  completed: false
},
{
  text: 'Some with React',
  completed: false
}
];
function App() {
  const [searchValue, setState] = React.useState('');
  
  const [todos, setTodos] = React.useState(todosList);
  const completedTodos = todos.filter(todo => todo.completed).length;
  const totalTodos = todos.length || todosList.length;


  const handleSearch = () => { return todos.filter(todo => todo.text.toLowerCase().includes(searchValue.toLowerCase())); };
  const todosFiltered = searchValue.length > 0 ? handleSearch() : todos;


  return (
    <React.Fragment>
          <TodoCounter todo={totalTodos} completed={completedTodos}></TodoCounter>
          <TodoSearch setState={setState} searchValue={searchValue}></TodoSearch>
          <CreateTodoButton></CreateTodoButton>
          <TodoList>
            { todosFiltered.map( todo => (<TodoItem key={todo.text} text={todo.text} completed={todo.completed}/> )) }
          </TodoList>
    </React.Fragment>
  );
}

export default App;

En mi versión del app incluí un filtro para saber cuales Todos están pendientes y cuáles completos. En código esto lo resolví de la siguiente manera:

if(!searchValue.length >= 1){
    searchedTodos = (isChecked)
      ? todos.filter(todo => !!todo.completed)
      : todos.filter(todo => !todo.completed)
  }else{
    searchedTodos = todos.filter(todo => {
      return todo.text.toLowerCase().includes(searchValue.toLowerCase());
    })
  }

aquí como lo hice 😃

Me exploto la cabeza esta clase!

sencillamente bien explicado el poder de react

  const filteredTodoList = todoList.filter((todo) => {
    const value = searchValue.trim().toLowerCase();
    const todoText = todo.text.trim().toLowerCase();

    if (value) {
      return todoText.includes(value) ? todo : undefined;
    }
    
    return todo;
  });

Tengo instalado el github copilot y me autogenero el código 😬😬

        {
          todos.map(todo=>
            {
              if(todo.text.toLowerCase().includes(searchValue.toLowerCase()))
                return <TodoItem key={todo.text} text={todo.text} completed={todo.completed}/>
            }
          )
        }

Esta es una forma de filtrar

Muy buena clase

Para solucionar el reto agregué un método .filter al componente TodoList antes del .map

<TodoList className="TodoList">
        {
            todos.filter((todo) => {
              return todo.text.includes(searchValue)
            }).map((todo) => (
              <TodoItem
                className="TodoItem"
                key={todo.text}
                text={todo.text}
                completed={todo.completed}
              />
              ))
          }
</TodoList>

Primera vez que veo usar un filter de esa forma, ln28

Les comparto el searchedTodos con condicional ternaria

    let searchTodos = !searchValue.length >= 1 ?
        todos : todos.filter(todo => {
            const todoText = todo.text.toLowerCase()
            const searchText = searchValue.toLowerCase()
            return todoText.includes(searchText)
        })

Mi solución para filtrar los Todos dependiendo de las letras que escriban los usuarios en el input <TodosSearch/>

  1. Primero Definir donde se están actualizando los caracteres ingresados por los usuarios:
    👉 Se encuentran en el estado searchValue

console.log(searchValue) //  Caracteres ingresados desde el input 
  1. Identificar donde se están enviando los Todos:
    Estamos enviando todos los Todos
{todos.map((todo) => (
          <TodoItem
            key={todo.text}
            text={todo.text}
            completed={todo.completed}
          />
        )}
  1. Para filtrar los Todos dependiendo de los caracteres ingresados por los usuarios usamos el metodo .filte()r
    El cual crea un nuevo Array con los elementos que pases la condición impuesta en la función:
  • Si no existen caracteres se mostraran todos los todos // return todo
  • Si nuestros Todos en su propierdad .text incluye caracteres ingresados desde input que identificamos gracias al estado searchValue. // Mostrar los Todos que incluyan los caracteres ingresados.

Usamos .toLowerCase() para filtrar sin importar que el usuario ingrese el texto en MAYUSCULAS o minusculas

todos.filter((todo) => {
          if (searchValue == "") {
            return todo
          } else if (todo.text.toLowerCase().includes(searchValue.toLowerCase())) {
            return todo
          }
        })
  1. Ahora sí usamos el metodo . map() crea un nuevo array con los resultados de la llamada a la función indicada aplicados a cada uno de sus elementos.
        {todos.filter((todo) => {
          if (searchValue == "") {
            //TODO: console.log(todo); // Array con todos los Todos y sus propiedades .text .completed
            //* console.log(todo.text); // No se retorna el Array filtado así=> todo.text porque el metodo .map lo renderiza en su propiedad ".text = todo.text"
            return todo
          } else if (todo.text.toLowerCase().includes(searchValue.toLowerCase())) {
            // console.log(searchValue.toLocaleLowerCase());
            return todo
          }
        }).map((todo) => (
          <TodoItem
            key={todo.text}
            text={todo.text}
            completed={todo.completed}
          />
        ))}

Resultado final 🔥

Solución para el filtrado

import React, { useState } from 'react';
import { Fragment } from "react";
import TodoCounter from "./TodoCounter";
import TodoSearch from "./TodoSearch";
import TodoList from "./TodoList";
import TodoItems from './TodoItems';
import CreateTodoButton from "./CreateTodoButton";
import todosMock from '../mock/todosMock.json'

const App = () => {
  const [searchValue, setSearchValue] = useState('');
  const [todos, setTodos] = useState(todosMock);
  const completedTodos = todos.filter(todo => todo.completed).length;
  const totalTodos = todos.length;
  let todosFiltered = todos
  if (searchValue)
    todosFiltered = todosMock.filter(todo => todo.text.toLowerCase().includes(searchValue));
  return (
    <Fragment>
      <TodoCounter 
        total={totalTodos}
        completed={completedTodos}
      />
      <TodoSearch searchValue={searchValue} setSearchValue={setSearchValue} />
      <TodoList>
        <TodoItems todos={todosFiltered} setTodos={setTodos} />
      </TodoList>
      <CreateTodoButton />
    </Fragment>
  );
};

export default App;

Solución para eliminar y marcar como completado las tareas

import React from 'react';
import TodoItem from "../TodoItem";

const renderTodoItems = ({ todos, setTodos }) => todos.map((todo) => {

  const onComplete = (text, completed) => {
    alert(`You complete the todo ${text}`);
    const todoMapped = todos.map(todo => (todo.text === text ? {
      text,
      completed: !completed
    } : todo))
    setTodos(todoMapped);
  };

  const onDelete = (text) => {
    let newTodos = todos.filter(todo => todo.text !== text);
    setTodos(newTodos);
  };


  return (
    <TodoItem
      key={todo.text}
      text={todo.text}
      completed={todo.completed}
      onComplete={onComplete}
      onDelete={onDelete}
    />
  );
});

const TodoItems = (props) => renderTodoItems(props);

export default TodoItems;

Repo

TODOs Web Application

Para el reto creé una lista de todos filtrados y simplemente hice el map con esa lista:

const todosFiltered = todos.filter(todo => todo.text.toLowerCase().includes(searchValue.toLowerCase()))

//entre los brackets de TodoList
{todosFiltered.map(todo => (
          <TodoItem 
          key={todo.text} 
          text={todo.text}
          completed={todo.completed} 
          />
        ))}

Este curso esta Genial 😃

const foundTodos = todos.filter(todo => (todo.text.toUpperCase()).includes(searchValue.toUpperCase()))

!! es la no false :v

Agregar un filtro de texto

const filtersTodos = todos.filter(todo => todo.text.startsWith(textSearched));

y pasar ese parametro a la lista:

<TodoList>
        {filtersTodos.map((todo, index) => (<TodoItem key={index} text={todo.text} completed={todo.completed}/>) )}
      </TodoList>

Here it is

<TodoList>
        {searchValue.length !== 0 ?  todos.filter(todo => todo.text.includes(searchValue)).map(todo => (<TodoItem text={todo.text} key={todo.text} completed={todo.compleated}/>)) :todos.map(todo => (
          <TodoItem text={todo.text} key={todo.text} completed={todo.compleated}/>
        ))}
      </TodoList>

Pienso que simplemente se puede utilizar la propiedad completed nada mas (sin el, !!), ya que esta es un booleano por lo tanto se contaran los true:

const completedTodos = todos.filter(todo => todo.completed).length;
import React from 'react';

import './TodoSearch.css';
function TodoSearch({state1,setState1}){
	
  const onSearchValueChange = (event) => {
    console.log(event.target.value);
    setState1(event.target.value.toLowerCase())
  };
  
  return (
    <React.Fragment>
    <input
      className="TodoSearch"
      placeholder="Cebolla"
      onChange={onSearchValueChange}
      value={state1}
      />
     <p>
      {state1}
       </p>
       </React.Fragment>
  );;
}

export {TodoSearch};

//import './App.css';

import React from "react";
import {TodoCounter} from "./component/TodoCounter";
import {TodoItem} from "./component/TodoItem";
import {TodoList} from "./component/TodoList";
import {TodoSearch} from "./component/TodoSearch";
import {NewTodo} from "./component/NewTodo";

const todos =[
  {text: 'cc',completed:false},
  {text: 'cc1',completed:false},
  {text: 'cc2',completed:true},
  {text: 'cc3',completed:false},
  {text: 'cc4',completed:false},
  {text: 'cc5',completed:true},
]

function App() {
  const [stateTodos,setStateTodos] = React.useState(todos)
  const [searchState,setSearchState1] = React.useState('')
  return (
    <React.Fragment>
      <TodoCounter stateTodos={stateTodos} />
      <TodoSearch state1={searchState} setState1={setSearchState1}/>
        <TodoList>
          {stateTodos.filter(todo => searchState == ""?true:todo.text.toLowerCase().includes(searchState) ).map((todo,key)=><TodoItem key={key} text={todo.text} completed={todo.completed} setStasetStateTodos= {setStateTodos}teTodos= {setStateTodos}></TodoItem>)}
        </TodoList>
        <NewTodo stateTodos ={stateTodos} setStateTodos= {setStateTodos} />
    </React.Fragment>
  );
}

export default App;

Yo hice diferente la función de borrar, usando filter, la dejo esperando a que a alguien le sirva.

const deleteTodo = ( text ) => {
    const newTodos = todos.filter( todo => todo.text !== text );
    setTodos(newTodos);
  };

Mi solución de los dos retos:

1. Search:

  • En caso de que no hayamos escrito nada se seguirán mostrando todos los Todos del arreglo original porque el método includes devuelve true cuando le pasamos un string vacío
const filteredTodos = todos.filter((todos) => {
    return todos.text.toLowerCase().includes(searchValue.toLowerCase());
  });

<TodoList>
        {filteredTodos.map((todo, i) => (
          <TodoItem
            key={i}
            text={todo.text}
            completed={todo.isCompleted}
          />
        ))}
      </TodoList>

2. Add y Delete:

  • Para el segundo reto tuve que pasar el estado todos y setTodos del componente App al componente TodoItem en los props para modificarlo directamente en la función onComplete y onDelete.
 const onComplete = () => {
    const newTodos = [...todos];
    newTodos[pos].isCompleted = !newTodos[pos].isCompleted;
    setTodos(newTodos);
  };

  const onDelete = () => {
    const newTodos = [...todos].filter((todo) => todo.text !== text);
    console.log(newTodos);
    setTodos(newTodos);
  };
Creo que el Sql quedo obsoleto xD

Okey… Tendre que ver este curso como 3 veces

Lo dijoooo!!! lo dijooooo!!!