I am creating an e-commerce website website and I need to create a button where the user can click and the product is added to the cart.
But before adding the product into the cart I need to show the loader inside the button so the user can wait for their product to be added to the cart.
The problem is that all the buttons are going to the loading state, instead of only the clicked one:
As you can see, in the above image all the loaders are shown which is not my approach.
My Code:
"use client";
const Products = () => {
const oval = (
// This is loader...
);
const dispatch = useDispatch();
const [products, setProducts] = useState<IProducts>();
const [loader, setLoader] = useState<JSX.Element | string>("ADD TO CART");
useLayoutEffect(() => {
// return products...
}, []);
const addToDatabase = async (product: IProducts, productId: string) => {
setLoader(oval);
try {
const res = await axios.post("/api/cart", { product });
if (res.status === 200) {
dispatch(addProduct(product));
} else {
alert("Something went wrong");
}
} catch (error) {
alert("INTERNAL SERVER ERROR");
console.log(error);
}
};
return (
<>
<div className="container">
<div className="">
{products &&
products.map((product: IProducts) => (
<div
key={product.id}
className=""
>
<Image
src={product.image}
width={100}
height={100}
alt={product.title}
/>
<h1 className="">{product.title}</h1>
<p className="">${product.price}</p>
<button
id={`product-${product.id}`}
className=""
onClick={() =>
addToDatabase(product, `product-${product.id}`)
}
>
<span>{loader}</span>
</button>
</div>
))}
</div>
</div>
</>
);
};
export default Products;
I just need to show the loader on the particular button not all the buttons.
2
Answers
There are two ways I imagine you can handle this, one is to create the cards a separate component that is mapped, this way each card would have its own state of the loader
Other way is to create a list of items that are being currently added, in this way your component instead of having a loader true or false state, will have an array state as
All the buttons are switching to the loading state because they are all referring to the same state. You could change slightly your logic, by having a
loadingProductId
state, like so: