I'm trying to make a shopping cart, the list of items contains different objects and each object has an id. It starts from 1 and ends on 9 (9 objects are there in the list.).
ex -
{
id: 1,
title: "Buttermilk Pancakes",
category: "breakfast",
price: 15.99,
img: "./images/item-1.jpeg",
desc: `I'm baby woke mlkshk wolf bitters live-edge blue bottle, hammock freegan copper mug whatever cold-pressed `,
},
So, calling the dispatch with action type = "REMOVE" gets the item's id. (In the payload I'm fetching the id attribute. )
Now I have the item's ID, but I'm trying to find a way to filter out just one instance of that ID (The cart could have the same item, added twice. If there are more than 1 items of the same type, it just shows up as a new item.) from the "state" array (the array that contains the current items in the cart).
But I can't find a way to remove just one instance of that item with the key/id of the item from the state array. I have tried using splice(index,1) but it still removes extra elements.
Here is the code - (Removed import lines that are not related to the issue.)
import { useReducer, useState } from "react";
export const CartValue = React.createContext();
function App() {
const [totalCartValue, setTotalCartValue] = useState(0);
const reducer = (state, action) => {
const item = menu[action.payload - 1];
switch (action.type) {
case "ADD":
setTotalCartValue(totalCartValue item.price);
return [...state, item];
case "REMOVE":
setTotalCartValue(totalCartValue - item.price);
state.splice(action.payload - 1, 1);
return state;
default:
throw new Error();
}
};
const [state, dispatch] = useReducer(reducer, []);
return (
<>
<CartValue.Provider value={{ reducer, dispatch, state, totalCartValue }}>
<Home></Home>
<Menu></Menu>
<Story></Story>
<Contact></Contact>
<Footer></Footer>
</CartValue.Provider>
</>
);
}
export default App;
Here is the map function that creates the cart list. (this is from a different component that is accessing the dispatch function with the use of use context.) -
{state.map((item) => {
const { id, title, price } = item;
return (
<div className="cartItem" key={id}>
<div className="cartItemDetails btnCommonDesign">
<p className="itemName">{title}</p>
<button
className="deleteCartItem"
onClick={() => {
dispatch({ type: "REMOVE", payload: id });
}}
>
<AiOutlineDelete size={18} />
</button>
</div>
<span className="cartItemPrice">${price}</span>
</div>
);
})}
CodePudding user response:
Splice works with array indexes and you are passing id
property of item object. Instead you could pass the actual index of the item
/* Use index from map function and pass that as payload */
{
state.map((item, idx) => {
const { id, title, price } = item;
return (
<div className="cartItem" key={id}>
<div className="cartItemDetails btnCommonDesign">
<p className="itemName">{title}</p>
<button
className="deleteCartItem"
onClick={() => {
dispatch({ type: "REMOVE", payload: idx });
}}
>
<AiOutlineDelete size={18} />
</button>
</div>
<span className="cartItemPrice">${price}</span>
</div>
);
});
}
In your reducer
function you can do this for case "REMOVE"
case "REMOVE":
setTotalCartValue(totalCartValue - item.price);
/* Instead of mutating original array you could create a copy of
that array and splice on it and return it in the state. */
const indexOfItemToBeRemoved = action.payload
const cart = [...state]
cart.splice(indexOfItemToBeRemoved, 1);
return [...cart];