React, context remove item from cart - reactjs

I have a demo here
Its a simple cart app where I'm listing products and then adding them to a cart components
It uses context for the app state.
I'd now like to be able to remove items from the cart but I'm struggling to get this to work.
Do I need to add a DeleteCartContext.Provider
import React, { useContext } from "react";
import { CartContext } from "./context";
import { IProduct } from "./interface";
const Cart = () => {
const items = useContext(CartContext);
const handleClick = (
e: React.MouseEvent<HTMLInputElement, MouseEvent>,
item: IProduct
) => {
e.preventDefault();
};
const cartItems = items.map((item, index) => (
<div>
<span key={index}>{`${item.name}: £${item.price}`}</span>
<input type="button" value="-" onClick={e => handleClick(e, item)} />
</div>
));
return (
<div>
<h2>Cart</h2>
{cartItems}
</div>
);
};
export default Cart;

There are many ways to control Items in Context so I tried to answer as similar to your structure, here is how you do that:
import React, { useContext } from "react";
import { CartContext, RemoveCartContext } from "./context";
import { IProduct } from "./interface";
const Cart = () => {
const items = useContext(CartContext);
const removeItem = useContext(RemoveCartContext);
const handleClick = (
e: React.MouseEvent<HTMLInputElement, MouseEvent>,
item: IProduct
) => {
e.preventDefault();
};
const cartItems = items.map((item, index) => (
<div>
<span key={index}>{`${item.name}: £${item.price}`}</span>
<input type="button" value="+" onClick={e => handleClick(e, item)} />
<input type="button" value="-" onClick={e => removeItem(item)} />
</div>
));
return (
<div>
<h2>Cart</h2>
{cartItems}
</div>
);
};
export default Cart;
import React, { createContext, useCallback, useRef, useState } from "react";
export const CartContext = createContext([]);
export const AddCartContext = createContext(item => {});
export const RemoveCartContext = createContext(item => {});
export const CartProvider = ({ children }) => {
const [items, setItems] = useState([]);
const itemsRef = useRef(items);
itemsRef.current = items;
return (
<AddCartContext.Provider
value={useCallback(item => {
setItems([...itemsRef.current, item]);
}, [])}
>
<RemoveCartContext.Provider
value={useCallback(item => {
const newItems = itemsRef.current.filter(
_item => _item.id !== item.id
);
setItems(newItems);
}, [])}
>
<CartContext.Provider value={items}>{children}</CartContext.Provider>
</RemoveCartContext.Provider>
</AddCartContext.Provider>
);
};
and here is a working demo: https://stackblitz.com/edit/react-ts-cart-context-mt-ytfwfv?file=context.tsx

Related

React Outside Hook not reacting to outside Click

I am finishing up a project where I want to use a small dropdown menu when I click on my settings icon. The problem is that for some reason it is not recognized when I click outside of that dropdown menu. I used a hook that worked in the same project with a different dropdown menu, but now it doesn't. Maybe because it is in a modal? I really don't know.
Here is the Repo of this Project: https://github.com/Clytax/fem-kanban
The Hook (I modified it a bit by excluding the elipsis icon so it doesnt reopen when Click on it to close it.)
import React from "react";
export const useOutsideClick = (callback, exclude) => {
const ref = React.useRef();
React.useEffect(() => {
const handleClick = (e) => {
if (
ref.current &&
!ref.current.contains(e.target) &&
!exclude.current.contains(e.target)
) {
callback();
}
};
document.addEventListener("click", handleClick);
return () => {
document.removeEventListener("click", handleClick);
};
}, [callback, exclude]);
return ref;
};
The Modal:
import React, { useRef, useState, useEffect } from "react";
import "./taskModal.scss";
import { ReactComponent as Elipsis } from "../../../assets/Icons/icon-vertical-ellipsis.svg";
import { ReactComponent as Close } from "../../../assets/Icons/icon-chevron-up.svg";
import { ReactComponent as Open } from "../../../assets/Icons/icon-chevron-down.svg";
import { useSelector, useDispatch } from "react-redux";
import modalSlice, {
closeViewTaskModal,
openEditTaskModal,
closeAllModals,
openDeleteTaskModal,
} from "../../../features/global/modalSlice";
import Backdrop from "../Backdrop/Backdrop";
import Subtask from "../../Task/Subtask";
import "../../Extra/DropdownSettings.scss";
import { useOutsideClick } from "../../../hooks/useOutsideClick";
import { motion } from "framer-motion";
import DropdownStatus from "../../Extra/DropdownStatus";
import DropdownSettings from "../../Extra/DropdownSettings";
import DropdownSettingsTask from "../../Extra/DropdownSettingsTask";
const ViewTaskModal = ({ handleClose }) => {
const [openSettings, setOpenSettings] = useState(false);
const dispatch = useDispatch();
const task = useSelector((state) => state.modal.viewTaskModal.task);
const handleCloseSettings = () => {
console.log("hi");
setOpenSettings(false);
};
const modal = useSelector((state) => state.modal);
const viewTaskModal = useSelector((state) => state.modal.viewTaskModal);
const elipsisRef = useRef(null);
const wrapperRef = useOutsideClick(handleCloseSettings, elipsisRef);
const getFinishedSubTasks = () => {
let finishedSubTasks = 0;
task.subTasks.forEach((subtask) => {
if (subtask.isDone) {
finishedSubTasks++;
}
});
return finishedSubTasks;
};
const closeModal = () => {
dispatch(closeViewTaskModal());
};
return (
<Backdrop onClick={closeModal} mobile={false}>
<motion.div
onClick={(e) => {
e.stopPropagation();
}}
onMouseDown={(e) => {
e.stopPropagation();
}}
className="view-task"
>
<div className="view-task__header | flex">
<h2 className="view-task__header__title">{task.name}</h2>
<div className="view-tastk__settings">
<div
className="view-task__header__icon"
style={{ cursor: "pointer" }}
ref={elipsisRef}
onClick={() => {
setOpenSettings(!openSettings);
}}
>
<Elipsis />
</div>
{openSettings && (
<div className="dropdown-settings__task" ref={wrapperRef}>
<div
className="dropdown-settings__item"
onClick={() => {
dispatch(closeAllModals());
dispatch(openEditTaskModal(task));
}}
>
Edit Task
</div>
<div
className="dropdown-settings__item"
onClick={() => {
dispatch(closeAllModals());
dispatch(openDeleteTaskModal(task));
}}
>
Delete Task
</div>
</div>
)}
</div>
</div>
<p className="view-task__description">{task.description}</p>
<div className="view-task__subtasks">
<p>
Subtasks ({getFinishedSubTasks()} of {task.subTasks.length})
</p>
<div className="view-task__subtasks__list">
{task.subTasks.map((subtask, index) => (
<Subtask
subtaskID={subtask.id}
boardID={task.boardID}
taskID={task.id}
columnID={task.columnID}
key={index}
/>
))}
</div>
</div>
<div className="view-task__status">
<p>Current Status</p>
<DropdownStatus click={handleCloseSettings} task={task} />
</div>
</motion.div>
</Backdrop>
);
};
export default ViewTaskModal;

How can I display the result of the child component in the parent component?

my application consists of a filter select by provinces, the filter is a modal that shows me the result in the filter component (child), I would like to show the result in the parent not in the filter modal. I do not know what to pass to the parent to show the result or how to show it on the screen.
///parent component
import React, { useState, useEffect } from 'react'
import { useDispatch } from "react-redux";
import { getClinic } from '../../api/drupalAPI'
import {Clinic} from '#icofcv/common';
import { selectClinics } from '../../actions/detailClinics'
import { useNavigate } from "react-router-dom";
import contentUtils from '../../lib/contentUtils'
import { SearchFilterClinics } from './SearchFilterClinics'
import Button from 'react-bootstrap/Button';
import Form from 'react-bootstrap/Form';
const ClinicList = () => {
const [clinicList, setClinicList] = useState<Clinic[]>([]);
const [clinicListFiltered, setClinicListFiltered] = useState<Clinic[]>([]);
const [searchClinic, setSearchClinic] = useState("");
const dispatch = useDispatch();
const navigate = useNavigate();
///modal control
const [isOpen, setIsOpen] = useState(false);
const openModal = () => setIsOpen(true);
const closeModal = () => setIsOpen(false);
console.log(searchClinic);
const fetchClinicList = async () => {
getClinic().then((response)=>{
console.log(response)
setClinicList(response);
setClinicListFiltered(response)
}).catch ( (error) => {
console.error(error);
throw error;
});
}
const handleChange=e=>{
setSearchClinic(e.target.value);
filter(e.target.value);
}
const filter=(termSearch)=>{
const resultSearch= clinicList.filter((element)=>{
if(element.title.toString().toLowerCase().includes(termSearch.toLowerCase())
){
return element;
}
});
setClinicListFiltered(resultSearch);
}
function handleAddToDetail(clinic) {
dispatch(selectClinics(clinic));
navigate('clinicdetail');
}
function goToPageSearchFilterClinics() {
navigate('filterclinics');
}
useEffect (() => {
fetchClinicList();
}, []);
return(
<>
<div style={{display: 'flex'}}>
<div style={{width:'5rem'}}>
{/* <button onClick={() => goToPageSearchFilterClinics()}>filtro</button> */}
<button onClick={openModal}>filtro</button>
</div>
< SearchFilterClinics isOpen={isOpen} closeModal={closeModal} clinicFilter={clinicFilter}></SearchFilterClinics>
<Form className="d-flex">
<Form.Control
type="search"
value={searchClinic}
placeholder="Search"
className="me-2"
aria-label="Search"
onChange={handleChange}
/>
</Form>
</div>
<div className="content-cliniclist">
{
clinicListFiltered.map((clinic) => (
<div style={{marginBottom: '3rem'}}>
<button
type="button"
onClick={() => handleAddToDetail(clinic)}
style={{all: 'unset'}}
>
<div>
{/* <img src={ contentUtils.getLargeImageUrl(clinic.logoWidth )} alt="#"></img> */}
<div>{clinic.title}</div>
<div>{clinic.propsPhone}</div>
<div>{clinic.mobile}</div>
<div>{clinic.email}</div>
<div>{clinic.registry}</div>
</div>
</button>
</div>
))
}
</div>
</>
)
}
export default ClinicList;
////child component
import React, { useState, useEffect } from 'react'
import Select, { SingleValue } from 'react-select'
import { getClinic } from '../../api/drupalAPI'
import {Clinic} from '#icofcv/common';
import "./Modal.css";
interface Props {
isOpen: boolean,
clinicFilter: String,
closeModal: () => void
}
export const SearchFilterClinics : React.FC<Props> = ({ children, isOpen, closeModal, clinicFilter }) => {
////filter
type OptionType = {
value: string;
label: string;
};
const provincesList: OptionType[] = [
{ value: 'Todos', label: 'Todos' },
{ value: 'Valencia', label: 'Valencia' },
{ value: 'Castellon', label: 'Castellon' },
{ value: 'Alicante', label: 'Alicante' },
]
const [clinicList, setClinicList] = useState<Clinic[]>([]);
const [clinicListFilteredSelect, setClinicListFilteredSelect] = useState<Clinic[]>([]);
const [filterSelectClinic, setFilterSelectClinic] = useState<SingleValue<OptionType>>(provincesList[0]);
const handleChangeSelect = async (provinceList: SingleValue<OptionType>) => {
getClinic().then((response) => {
setClinicList(response);
setClinicListFilteredSelect(response)
setFilterSelectClinic(provinceList);
filterSelect(provinceList );
}).catch ((error) => {
console.error(error);
throw error;
});
}
const filterSelect=(termSearch)=>{
const resultFilterSelect = clinicList.filter((element) => {
if(element.province?.toString().toLowerCase().includes(termSearch.value.toLowerCase() )
){
return element;
}
});
setClinicListFilteredSelect(resultFilterSelect);
}
const handleModalContainerClick = (e) => e.stopPropagation();
return (
<>
<div className={`modal ${isOpen && "is-open"}`} onClick={closeModal}>
<div className="modal-container" onClick={handleModalContainerClick}>
<button className="modal-close" onClick={closeModal}>x</button>
{children}
<div>
<h1>Encuentra tu clínica</h1>
</div>
<div>
<form>
<label>Provincia</label>
<Select
defaultValue={filterSelectClinic}
options={provincesList}
onChange={handleChangeSelect}
/>
</form>
{
clinicListFilteredSelect.map((clinicFilter) => (
<div>
<div>{clinicFilter.title}</div>
<div>{clinicFilter.propsPhone}</div>
<div>{clinicFilter.mobile}</div>
<div>{clinicFilter.email}</div>
<div>{clinicFilter.province} </div>
<div>{clinicFilter.registry}</div>
</div>
))
}
</div>
</div>
</div>
</>
)
}
You need to pass a callback function to the parent and set the state value in the parent, not in the child. (This is known as lifting state up.)
In your case this would involve moving
const [filterSelectClinic, setFilterSelectClinic] = useState<SingleValue<OptionType>>(provincesList[0]);
Into the parent component. Then passing the setFilterSelectClinic function into the child component.
<SearchFilterClinics setFilterSelectClinic={(value) => setFilterSelectClinic(value)} isOpen={isOpen} closeModal={closeModal} clinicFilter={clinicFilter}/>
The value (within the parenthesis) is being passed up by the child component. This is the value you set here:
getClinic().then((response) => {
...
// this is the function we pass in from the parent. It set's the value
// of the callback function to provinceList
setFilterSelectClinic(provinceList);
...
We then setFilterSelectClinic to that value. Meaning filterSelectClinic now has the value passed up in the callback.

Change of icon in favorites

I try to change the icon and add it to favorites when I click on it. It works fine, my icon is changed but it impacts all my images icons instead of one. How can I fix this? Here is my code:
import React, { useState, useEffect } from "react";
import AddCircleOutlineIcon from '#mui/icons-material/AddCircleOutline';
import CheckCircleOutlineIcon from '#mui/icons-material/CheckCircleOutline';
import ExpandCircleDownIcon from '#mui/icons-material/ExpandCircleDown';
import PlayCircleIcon from '#mui/icons-material/PlayCircle';
const Row = () => {
const [image, setImage] = useState([])
const [favorite, setFavorite] = useState(false);
useEffect(() => {
...
}, []);
const addToFavorite = () => {
...
}
return (
<div >
{image.map((item) => {
return (
<div key={item.id}>
<span>{item.title}</span>
<span>{item.description}</span>
<img src={...} alt={image.title}/>
<div onClick={() => setFavorite(!favorite)}>
{favorite ? < CheckCircleOutlineIcon onClick={() => addToFavorite()} /> : < AddCircleOutlineIcon onClick={() => addToFavorite()} />}
</div>
)
})}
</div>
);
}
export default Row;
Your problem is favorite state is only true/false value, when it's true, all images will have the same favorite value.
The potential fix can be that you should check favorite based on item.id instead of true/false value
Note that I added updateFavorite function for handling favorite state changes on your onClick
Here is the implementation for multiple favorite items
import React, { useState, useEffect } from "react";
import AddCircleOutlineIcon from '#mui/icons-material/AddCircleOutline';
import CheckCircleOutlineIcon from '#mui/icons-material/CheckCircleOutline';
import ExpandCircleDownIcon from '#mui/icons-material/ExpandCircleDown';
import PlayCircleIcon from '#mui/icons-material/PlayCircle';
const Row = () => {
const [image, setImage] = useState([])
const [favorite, setFavorite] = useState([]);
useEffect(() => {
...
}, []);
const updateFavorite = (itemId) => {
let updatedFavorite = [...favorite]
if(!updatedFavorite.includes(itemId)) {
updatedFavorite = [...favorite, itemId]
} else {
updatedFavorite = updatedFavorite.filter(favoriteItem => itemId !== favoriteItem)
}
setFavorite(updatedFavorite)
}
const addToFavorite = () => {
...
}
return (
<div >
{image.map((item) => {
return (
<div key={item.id}>
<span>{item.title}</span>
<span>{item.description}</span>
<img src={...} alt={image.title}/>
<div onClick={() => updateFavorite(item.id)}>
{favorite.includes(item.id) ? < CheckCircleOutlineIcon onClick={() => addToFavorite()} /> : < AddCircleOutlineIcon onClick={() => addToFavorite()} />}
</div>
)
})}
</div>
);
}
export default Row;
Here is the implementation for a single favorite item
import React, { useState, useEffect } from "react";
import AddCircleOutlineIcon from '#mui/icons-material/AddCircleOutline';
import CheckCircleOutlineIcon from '#mui/icons-material/CheckCircleOutline';
import ExpandCircleDownIcon from '#mui/icons-material/ExpandCircleDown';
import PlayCircleIcon from '#mui/icons-material/PlayCircle';
const Row = () => {
const [image, setImage] = useState([])
const [favorite, setFavorite] = useState(); //the default value is no favorite item initially
useEffect(() => {
...
}, []);
const updateFavorite = (itemId) => {
let updatedFavorite = favorite
if(itemId !== updatedFavorite) {
updatedFavorite = itemId
} else {
updatedFavorite = null
}
setFavorite(updatedFavorite)
}
const addToFavorite = () => {
...
}
return (
<div >
{image.map((item) => {
return (
<div key={item.id}>
<span>{item.title}</span>
<span>{item.description}</span>
<img src={...} alt={image.title}/>
<div onClick={() => updateFavorite(item.id)}>
{favorite === item.id ? < CheckCircleOutlineIcon onClick={() => addToFavorite()} /> : < AddCircleOutlineIcon onClick={() => addToFavorite()} />}
</div>
)
})}
</div>
);
}
export default Row;
This is what you're looking for based on the code you've provided:
import { useState, useEffect } from "react";
const Item = ({ item }) => {
const [favorite, setFavorite] = useState(false);
const toggleFavorite = () => setFavorite((favorite) => !favorite);
return (
<div>
<span>{item.title}</span>
<span>{item.description}</span>
<span onClick={toggleFavorite>
{favorite ? "[♥]" : "[♡]"}
</span>
</div>
);
};
const Row = () => {
const [items, setItems] = useState([]);
useEffect(() => {
// use setItems on mount
}, []);
return (
<div>
{items.map((item) => <Item item={item} key={item.id} />)}
</div>
);
};
export default Row;
You can break up your code into smaller components that have their own states and that's what I did with the logic that concerns a single item. I've created a new component that has its own state (favorited or not).

How to filter or search for services in another component (React)

NOTE: My Page Card component is working correctly. How can I filter the card page component in the Search component?
I'm new to react, and I don't quite understand how I can accomplish this task.
In the Search component I put it in a fixed way, as I can't filter a component using another.
The Code is summarized for ease.
Card Page
import React, {
useEffect,
useState
} from "react";
import classes from "./boxService.module.css";
import axios from "axios";
function BoxService() {
const [test, SetTest] = useState([]);
useEffect(() => {
axios
.get("http://localhost:8080/api/test")
.then((response) => {
SetTest(response.data);
})
.catch(() => {
console.log("Error!");
});
}, []);
return ({
test.map((test, key) => {
<div className={classes.box}
return (
<Grid item xs = {2} key={key} >
<div className={test.name} < div >
<p className={test.description}</p>
</Grid>
);
})}
);
}
export default BoxService;
Seach Page
import React, {
useState,
useEffect
} from "react";
import axios from "axios";
function Search() {
const [searchTerm, setSearchTerm] = useState("");
const [test, SetTest] = useState([]);
//Chamada API
useEffect(() => {
axios
.get("http://localhost:8080/api/test")
.then((response) => {
SetTest(response.data);
})
.catch(() => {
console.log("Error");
});
}, []);
return (
<div>
<input type = "text"
placeholder = "Search..."
onChange = {
(event) => {
setSearchTerm(event.target.value);
}
}/>
{
test.filter((val) => {
if (searchTerm === "") {
return val;
} else if (
val.nome.toLowerCase().includes(searchTerm.toLowerCase())
) {return val;}
}).map((val, key) => {
return ( <div className = "user"
key = {key} >
<p> {val.name} </p> </div>
);
})
} </div>
);
}
export default Search;
Here is an example of how it should/could look like:
import React from "react";
function SearchBox({ setSearchTerm, searchTerm }) {
const handleFilter = (e) => {
setSearchTerm(e.target.value);
};
return (
<>
filter
<input type="search" onChange={handleFilter} value={searchTerm} />
</>
);
}
export default function App() {
const [searchTerm, setSearchTerm] = React.useState("");
const [filteredResults, setFilteredResults] = React.useState([]);
const [results, setResults] = React.useState([]);
React.useEffect(() => {
const fetchdata = async () => {
const randomList = await fetch(`https://randomuser.me/api/?results=50`);
const data = await randomList.json();
const { results } = data;
setResults(results);
};
fetchdata();
}, []);
React.useEffect(() => {
const filterResults = results.filter((item) =>
item.name.last.toLowerCase().includes(searchTerm.toLowerCase())
);
setFilteredResults(filterResults);
}, [searchTerm, results]);
return (
<div className="App">
<SearchBox setSearchTerm={setSearchTerm} searchTerm={searchTerm} />
<div>
<ul>
{filteredResults.map(({ name }, idx) => {
return (
<li key={idx}>
{name.first} {name.last}
</li>
);
})}
</ul>
</div>
</div>
);
}

How can I pass my Todo component Data into my Todolist component using React hooks?

Here is a link https://codesandbox.io/s/fast-architecture-45u4m?file=/src/Todo.js
I added comments showing which code I am trying to move into a separate component.
So I have this todo app and the original code has all of my functions and logic in one component called TodoList.js
I'm trying to refactor my code, so that all the logic for the todo is in a separate component called Todo.js
Here is what the code looks like
<>
{todos.map(todo => (
<div className='todo-row'>
<div
key={todo.id}
className={todo.isComplete ? 'complete' : ''}
key={todo.id}
onClick={() => completeTodo(todo.id)}
>
{todo.text}
</div>
<FaWindowClose onClick={() => removeTodo(todo.id)} />
</div>
))}
</>
So I have this TodoList.js component with all of my state and functions, but when I tried to remove my todo code, I can't seem to figure out how to refactor it, so that the same data still gets passed in and I am able to use all of my functions again
function TodoList() {
const [todos, setTodos] = useState([]);
const addTodo = todo => {
if (!todo.text || /^\s*$/.test(todo.text)) {
return;
}
const newTodos = [todo, ...todos];
setTodos(newTodos);
console.log(newTodos);
};
const removeTodo = id => {
const removedArr = [...todos].filter(todoId => todoId.id !== id);
setTodos(removedArr);
};
const completeTodo = id => {
let updatedTodos = todos.map(todo => {
if (todo.id === id) {
todo.isComplete = !todo.isComplete;
}
return todo;
});
setTodos(updatedTodos);
};
return (
<>
<TodoForm onSubmit={addTodo} />
<Todo />
</>
);
}
export default TodoList;
Originally, I replaced the component <Todo /> with the code I showed above in the first block. But now I wanna move all of that code into it's own component called Todo.js and then pass it in from there, but I'm running into errors because I have all my functions and state logic inside of the TodoList.js component
As per your sandbox . You just need to pass Props:
Todo.js
// I want to move this code into this component
import React from "react";
import { FaWindowClose } from "react-icons/fa";
const Todo = ({ todos, completeTodo, removeTodo }) => {
return todos.map((todo) => (
<div className="todo-row">
<div
key={todo.id}
className={todo.isComplete ? "complete" : ""}
onClick={() => completeTodo(todo.id)}
>
{todo.text}
</div>
<FaWindowClose onClick={() => removeTodo(todo.id)} />
</div>
));
};
export default Todo;
TodoList.js
import React, { useState } from "react";
import TodoForm from "./TodoForm";
import Todo from "./Todo";
import { FaWindowClose } from "react-icons/fa";
function TodoList({ onClick }) {
const [todos, setTodos] = useState([]);
const addTodo = (todo) => {
if (!todo.text || /^\s*$/.test(todo.text)) {
return;
}
const newTodos = [todo, ...todos];
setTodos(newTodos);
console.log(newTodos);
};
const removeTodo = (id) => {
const removedArr = [...todos].filter((todoId) => todoId.id !== id);
setTodos(removedArr);
};
const completeTodo = (id) => {
let updatedTodos = todos.map((todo) => {
if (todo.id === id) {
todo.isComplete = !todo.isComplete;
}
return todo;
});
setTodos(updatedTodos);
};
return (
<>
<TodoForm onSubmit={addTodo} />
{/* I want to move this code below into a new component called Todo.js */}
<Todo todos={todos} completeTodo={completeTodo} removeTodo={removeTodo} />
</>
);
}
export default TodoList;
Here is the demo : https://codesandbox.io/s/nostalgic-silence-idm21?file=/src/TodoList.js:0-1039
You can pass data and required functions to Todo component through props from TodoList component and Todo component should represent only on Todo item as per name so map should stay in TodoList component so after changes
TodoList.js
function TodoList() {
const [todos, setTodos] = useState([]);
const addTodo = todo => {
if (!todo.text || /^\s*$/.test(todo.text)) {
return;
}
const newTodos = [todo, ...todos];
setTodos(newTodos);
console.log(newTodos);
};
const removeTodo = id => {
const removedArr = [...todos].filter(todoId => todoId.id !== id);
setTodos(removedArr);
};
const completeTodo = id => {
let updatedTodos = todos.map(todo => {
if (todo.id === id) {
todo.isComplete = !todo.isComplete;
}
return todo;
});
setTodos(updatedTodos);
};
return (
<>
<TodoForm onSubmit={addTodo} />
{
todos.map(todo => <Todo to do = {todo} removeTodo={removeTodo} completeTodo={completeTodo}/>)
}
</>
);
}
export default TodoList;
And Todo.js
const {todo} = props;
return (
<div className='todo-row'>
<div
key={todo.id}
className={todo.isComplete ? 'complete' : ''}
key={todo.id}
onClick={() => props.completeTodo(todo.id)}
>
{todo.text}
</div>
<FaWindowClose onClick={() => props.removeTodo(todo.id)} />
</div>
);

Resources