CartPage.jsx
const [cart, setCart, cartTotal] = useCart()
return (
{cart?.map((p) => (
<div className="item" key={p._id}>
<div className="item-product">
<img src={`http://localhost:4000/api/product/photo/${p._id}`}
alt={p.name} width={"200px"} height={"200px"} />
<div className="item-detail">
<h4>{p.name} x {p.quantity}</h4>
<p>{p.description}</p>
<h4>Price: ${p.price}</h4>
<div className="qtyBtns">
<button className='increaseQtyBtn'
onClick={() => {
setCart(
cart.map((c) => {
if(c._id === p._id){
return {...c, quantity: c.quantity++}
}
})
)
localStorage.setItem(
"cart",
JSON.stringify([...cart ])
)
}}>
+
</button>
<button className='decreaseQtyBtn'
onClick={() => {
setCart(
cart.map((c) => {
if(c._id === p._id){
if(c.quantity === 1){
setCart(
cart.filter((c) => c._id !== p._id)
)
} else{
return {...c, quantity: c.quantity--}
}
}
})
)
localStorage.setItem(
"cart",
JSON.stringify([...cart ])
)
}}>-</button>
</div>
{/* <h4>Quantity: 1</h4> */}
</div>
</div>
<button>Remove</button>
</div>
))}
)
context/cart.jsx
import { useState, useContext, createContext, useEffect } from "react";
const CartContext = createContext()
const CartProvider = ({ children }) => {
const [cart,setCart] = useState([])
const cartTotal = cart.reduce((total, item) => total + item.quantity, 0)
useEffect(() => {
let existingCartItems = localStorage.getItem("cart")
if(existingCartItems) setCart(JSON.parse(existingCartItems))
}, [])
console.log(cartTotal)
return (
<CartContext.Provider value={[ cart, setCart, cartTotal ]}>
{children}
</CartContext.Provider>
)
}
const useCart = () => useContext(CartContext)
export { useCart, CartProvider }
Header.jsx
const Header = () => {
const [ cart, setCart, cartTotal ] = useCart()
return (
<Badge count={cartTotal} showZero>
<NavLink className="link" to="/cart">
Cart
</NavLink>
</Badge>
)
I am trying to update the quantity value by clicking the buttons + and – but I need to refresh the page at least once in order to have the value in header updating the value of quantity. May I ask any solutions can have the quantity value updated after clicking the buttons without any refresh?
2
Answers
This is a good use case for
useSyncExternalStore
in React v18. Subscribe to changes inlocalStorage
and return a snapshot when changes happen:You should use prefix increment. This is because when you use postfix increment for
{...c, quantity: c.quantity++}
, it will return c.quantity in quantity field, then it update c.quantity++. Therefore you see c.quantity only. So you should use{...c, quantity: ++c.quantity}
so it can update the c.quantity first then apply to quantity value