I have a simple app written in React 17.0.2 which takes values of grocery items from an object and calculates their total cost, displaying it dynamically using setState — up to a total of 10 of any one item. That part is all working fine (I think), but I can’t get my reset button to work.
I’ve spent hours Googling and I’ve tried using useEffect but it didn’t update the values on clicking the reset button.
My code is as below (you can ignore the Tailwind classes; I can’t seem to get that to work in CodeSandbox).
import "./styles.css";
import { useState } from "react";
const groceryItems = [
{ id: 0, type: "Bread", price: 3, count: 0 },
{ id: 1, type: "Milk", price: 2.5, count: 0 },
{ id: 2, type: "Cheese", price: 17.5, count: 0 }
];
const MAX_ITEM_COUNT = 10;
export default function App() {
const [counters, setCounter] = useState(groceryItems);
const sum = groceryItems.reduce(
(acc, itemPrices) => acc + itemPrices.count * itemPrices.price,
0
);
const decrementCounter = (item) => {
if (item.count === 0) {
return;
}
const newState = counters.map((counter) => {
if (counter.id === item.id) {
return { ...counter, count: item.count-- };
} else {
return counter;
}
});
setCounter(newState);
};
const incrementCounter = (item) => {
if (item.count === MAX_ITEM_COUNT) {
return;
}
const newState = counters.map((counter) => {
if (counter.id === item.id) {
return { ...counter, count: item.count++ };
} else {
return counter;
}
});
setCounter(newState);
};
const resetCounters = () => {
const newState = counters.map((counter) => {
return { ...counter, count: 0 };
});
setCounter(newState);
};
return (
<main className="first-of-type:pt-20 last-of-type:pb-56 space-y-10 mx-auto max-w-4xl">
<h1 className="text-xl text-center">Groceries</h1>
<div id="items-description" className="px-10 text-center">
Choose your quantity of items below.
<br />
You may select a maximum of {MAX_ITEM_COUNT} items of each type.
</div>
<div className="item-chooser flex flex-col border mx-10 md:mx-36 py-10 space-y-14">
{groceryItems.map((item) => (
<div
className="flex flex-col md:flex-row mx-20 text-center place-items-center md:place-items-start"
key={item.id}
>
<div className="item-type sm:w-1/3 md:text-right">{item.type}</div>
<div className="item-price sm:w-1/3 md-text-left">
{"$" + item.price.toFixed(2)}
</div>
<div className="buttons-counter flex flex-row text-center sm:w-1/4 md:ml-10 space-x-3">
<button
className="button decrement sm:w-1/3"
onClick={() => decrementCounter(item)}
>
-
</button>
<div className="item-quantity sm:w-1/3"> {item.count} </div>
<button
className="button increment sm:w-1/3"
onClick={() => incrementCounter(item)}
>
+
</button>
</div>
</div>
))}
<div className="flex flex-row mx-20">
<div className="spacer sm:w-1/3"></div>
<div className="spacer sm:w-1/3"></div>
<div className="reset-button flex sm:w-1/4 md:ml-10 space-x-3 m-auto text-center">
<div className="spacer sm:w-1/3"></div>
<button className="reset sm:w-1/3" onClick={resetCounters}>
Reset
</button>
<div className="spacer sm:w-1/3"></div>
</div>
</div>
<div className="flex flex-row mx-20 space-x-5 place-items-center">
<div className="flex-auto uppercase font-bold text-right">Total</div>
<div className="flex-auto">${sum.toFixed(2)}</div>
</div>
</div>
</main>
);
}