💚 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.
Primeros pasos con React
Cómo aprender React.js
Cuándo usar React.js
Cambios en React 18: ReactDOM.createRoot
Instalación con Create React App
Fundamentos de React: maquetación
JSX: componentes vs. elementos (y props vs. atributos)
Componentes de TODO Machine
CSS en React
Fundamentos de React: interacción
Manejo de eventos
Manejo del estado
Contando y buscando TODOs
Completando y eliminando TODOs
Fundamentos de React: escalabilidad
Organización de archivos y carpetas
Persistencia de datos con Local Storage
Custom Hook para Local Storage
Manejo de efectos
React Context: estado compartido
useContext
Modales y formularios
Portales: teletransportación de componentes
Formulario para crear TODOs
Retos
Reto: loading skeletons
Reto: icon component
Próximos pasos
Deploy con GitHub Pages
Toma el Curso de React.js: Patrones de Render y Composición
Aún no tienes acceso a esta clase
Crea una cuenta y continúa viendo este curso
Aportes 81
Preguntas 12
💚 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.
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.
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());
})
}
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)
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
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)
})
console.log(searchValue) // Caracteres ingresados desde el input
{todos.map((todo) => (
<TodoItem
key={todo.text}
text={todo.text}
completed={todo.completed}
/>
)}
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
}
})
{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}
/>
))}
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;
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);
};
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>
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);
};
Okey… Tendre que ver este curso como 3 veces
Lo dijoooo!!! lo dijooooo!!!
¿Quieres ver más aportes, preguntas y respuestas de la comunidad? Crea una cuenta o inicia sesión.