I am trying to build a shopping cart that takes items and quantities from a form input adding to local storage and displays them as a list of items in another component. Each list has a checkbox which on checking I want to move the item to the checked list. I am hitting an infinite rerender when trying to add logic to add checked items in a checked list. Here is my code: sandbox https://codesandbox.io/s/fervent-carson-gchmtt?file=/src/App.jsAny help in resolving an issue will be much appreciated.
ShoppingItemList.js
import { React, useState, useCallback, useEffect } from "react";
import { Link } from "react-router-dom";
import "./ShoppingItemList.css";
const ShoppingItemList = (props) => {
const [checked, setChecked] = useState(props.shoppingList);
// useEffect(()=>{
// setChecked(props.shoppingList)
// },[])
// Add/Remove checked items from the list
const handleCheck = useCallback(
(index) => {
let updatedList = [...props.shoppingList];
updatedList[index].isSelected = !updatedList[index].isSelected;
setChecked(updatedList);
console.log("checked " checked);
},
[checked]
);
return (
<div className="container">
<div className="title">Shopping List:</div>
<div className="list-container">
{props.shoppingList.map((item, index) => (
<ul key={item.id}>
<input value={item} type="checkbox" onChange={handleCheck(index)} />
<div className="child">{item.item}</div>
<div className="child">{item.quantity}</div>
</ul>
))}
</div>
<Link to="/">Shopping Form</Link>
<br></br>
{/* <div>
{`Items checked are: ${checkedItems}`}
</div> */}
</div>
);
};
export default ShoppingItemList;
App.js
import { React, useState,useEffect } from "react";
import ShoppingListForm from "./Components/ShoppingListForm";
import ShoppingItemList from "./Components/ShoppingItemList";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
function App() {
let initShoppingItemList = JSON.parse(localStorage.getItem("shoppedItem") || "[]");
const [shoppingItem, setShoppingItem] = useState(initShoppingItemList);
const addShoppedItemHandler = (shoppedItem) => {
// const shoppingListWId = shoppingItem.map((n,i) => {
// return n['id'] = i;
// })
let id;
shoppingItem.length===0?id=0: id = shoppingItem[shoppingItem.length-1].id 1;
const shoppingListWId = {
id:id,
item:shoppedItem.item,
quantity:shoppedItem.quantity,
isSelected:shoppedItem.isSelected
};
//setShoppingItem(...shoppingItem,shoppingListWId)
setShoppingItem([...shoppingItem,shoppingListWId])
// setShoppingItem((prevShoppingItem) => {
// return [shoppingItem, ...prevShoppingItem];
// });
console.log(shoppingItem);
};
useEffect(() => {
if (initShoppingItemList !== 0)
localStorage.setItem("shoppedItem", JSON.stringify(shoppingItem));
},[initShoppingItemList,shoppingItem]);
return (
<Router>
<Routes>
<Route
path="/"
element={
<ShoppingListForm onSavedShoppingData={addShoppedItemHandler} />
}
/>
<Route
exact
path="/itemList"
element={<ShoppingItemList shoppingList={shoppingItem} />}
/>
</Routes>
</Router>
);
}
export default App;
ShoppingListForm.js
import { React, useState } from "react";
import { useNavigate } from "react-router-dom";
import "./ShoppingListForm.css";
const ShoppingListForm = (props) => {
const navigate = useNavigate();
const [enteredItem, setEnteredItem] = useState("");
const [enteredQuantity, setQuantity] = useState(0);
const itemChangeHandler = (event) => {
console.log("inputbox " event.target.value);
setEnteredItem(event.target.value);
};
const submitHandler = (event) => {
event.preventDefault();
let shoppingData;
if (enteredItem !== undefined && enteredQuantity !== 0) {
shoppingData = {
item: enteredItem,
quantity: enteredQuantity,
isSelected: false
};
props.onSavedShoppingData(shoppingData);
setEnteredItem("");
setQuantity("");
navigate("/itemList");
} else {
alert("Enter Item & select quantity");
}
};
const dropdownChangeHandler = (event) => {
console.log(event.target.value);
setQuantity(event.target.value);
};
return (
<form className="shop-item" onSubmit={submitHandler}>
<div className="shop-item__controls">
<div className="shop-item__control">
<label>Title</label>
<input
type="text"
value={enteredItem}
placeholder="Add an item..."
onChange={itemChangeHandler}
/>
</div>
<div className="shop-item__control">
<label>Item Quantity</label>
<select value={enteredQuantity} onChange={dropdownChangeHandler}>
<option value="0">0</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
</div>
</div>
<div className="shop-item__actions">
<button type="submit"> Save Item </button>
</div>
</form>
);
};
export default ShoppingListForm;
CodePudding user response:
Your call in ShoppingList.js is wrong. Instead of onchange={handleCheck(index)}
you need to make it an anonymous function to pass in an argument the way you have it: onChange={() =>
handleCheck(index)}`
Line 45 of ShoppingItemList.js
Your fixed sandbox: https://codesandbox.io/s/confident-wood-1jonhs