So I am building a shopping cart, I am done with most of my code but when I try to increment or decrement the value of a product quantity from cart it just fetches me the value of current quantity it doesn’t get updated. I am unable to understand where I am making the mistake.
This is my cart.js file
import React from 'react' import 'bootstrap/dist/css/bootstrap.min.css'; export default function Cart({ cart, setCart }) { const getTotalSum = () => { return cart.reduce( (sum, { cost, quantity }) => sum + cost * quantity, 0 ); }; const RemoveFromCart = productToRemove => { setCart(cart.filter(product => product !== productToRemove)); }; const clearCart = () => { setCart([]) } const setQuantity = (product, amount) => { const newCart = [...cart]; newCart.find(item => item.name === product.name) .quantity = amount; setCart(newCart) }; let valueCal =(v)=>{ console.log(v) return v++ } let decrement =(v)=>{ console.log(v) return v-- } return ( <> <h1>Cart</h1> {cart.length > 0 && (<button onClick={clearCart}>Clear Cart</button>)} <div className="products"> {cart.map((product, idx) => ( <div className="product" key={idx}> <h3>{product.name}</h3> <h4>RS: {product.cost}</h4> <img src={product.image} alt={product.name} /> Quantity: {product.quantity} <button value={product.quantity} onClick={(e) => setQuantity( product, parseInt(valueCal(e.target.value)) ) } >Add</button> <button value={product.quantity} onClick={(e) => setQuantity( product, parseInt(decrement(e.target.value)) ) } > Drop </button> <button onClick={() => RemoveFromCart(product)}> Remove </button> </div> ))} </div> <div> Total cost: Rs: {getTotalSum()} </div> </> ) }
Advertisement
Answer
Issue
The issue appears to be state mutation. When you find a matching product and set the quantity
property you are mutating the product object and since object is still shallow reference equal React bails on rerendering it. This is why you see stale UI.
const setQuantity = (product, amount) => { const newCart = [...cart]; newCart.find(item => item.name === product.name).quantity = amount; // mutation setCart(newCart) };
Additionally, the Array.prototype.find
method can potentially return undefined
if a matching product item isn’t found, and if this happens your code will throw an error when it attempts to access quantity
of undefined
.
You’ve also some odd logic around incrementing/decrementing the quantity by 1. Just add/subtract 1 from the quantity.
Solution
Shallow copy all state that is being updated.
const setQuantity = (product, amount) => { setCart(cart => cart.map(item => item.name === product.name ? { ...item, quantity: item.quantity + amount } : item)); };
Fix the button callbacks. Just let the amount
be what is added to the quantity.
<button onClick={(e) => setQuantity(product, 1)} > Add </button> <button onClick={(e) => setQuantity(product, -1)} > Drop </button