i'm using supabase as backend for my e-commerce project. so if i add item to cart, it works fine and CartItems component re-rendered successfully and showing the fresh data. But inside the cartItem component , if i tried to increase or decrease the quantity. On supabase , 'quantity' column is getting update as i click on any on two buttons to increase or decrease. But here inside the UI , quantity not getting update instantly. inshort, data is not being fetched again after mutations and cartItems component not getting re-rendered . I'm providing code below for all of my components also service functions that are responsible for making request. please help to resolve the issue
this function responsible for fetching cartItems.
export const getCartItems = async () => {
const {data, error} = await supabase.from('cart').select('*');
if(error) throw new Error(error.message)
return data
}
this function responsible to increase item's quantity.
export const increaseQuantity = async (itemId, itemPrice) => {
const {data:item, error: quantityUpadateError} = await supabase
.from('cart')
.select('quantity')
.eq('id', itemId)
.single()
if(quantityUpadateError) throw new Error(quantityUpadateError.message);
const increasedQuantity = item?.quantity + 1;
const increasedTotalPrice = itemPrice * increasedQuantity ;
const { error: quantityUpdationError } = await supabase
.from('cart')
.update({ quantity: increasedQuantity, total_price: increasedTotalPrice })
.eq('id', itemId);
if(quantityUpdationError) throw new Error(quantityUpdationError.message)
}
this function responsible to decrease item's quantity or to delete the row.
export const decreaseQuantity = async (itemId, itemPrice) => {
const {data: item, error: quantityUpadateError} = await supabase
.from('cart')
.select('*')
.eq('id', itemId)
.single()
if(quantityUpadateError) throw new Error(quantityUpadateError.message);
if(item?.quantity > 1) {
const decreasedQuantity = item?.quantity -1 ;
const decreasedTotalPrice = item?.total_price - itemPrice ;
const { error: quantityUpdationError } = await supabase
.from('cart')
.update({ quantity: decreasedQuantity, total_price: decreasedTotalPrice })
.eq('id', itemId);
if(quantityUpdationError) throw new Error(quantityUpdationError.message)
}else{
const { error } = await supabase
.from('cart')
.delete()
.eq('id', itemId)
if(error) throw new Error(error.message)
}
}
here is the custome hook for cartItems
import { useQuery } from "@tanstack/react-query";
import { getCartItems } from "../../services/ApiCart";
const useCart = () => {
const { data: cartItems, isLoading: loadingCart } = useQuery({
queryFn: getCartItems,
queryKey: ["cart"],
});
return { cartItems, loadingCart };
};
export default useCart;
here is the custome hook to update quantity
import { useMutation, useQueryClient } from "@tanstack/react-query"
import { decreaseQuantity, increaseQuantity } from "../../services/ApiCart"
export const useQuantity = () => {
const queryClient = useQueryClient()
function checkUpdation (item,change) {
if(change === 'increase') increaseQuantity(item.id, item.price)
if(change === 'decrease') decreaseQuantity(item?.id, item?.price)
}
const {mutate: updateQuantity, isLoading: updatingQuantity} = useMutation({
mutationFn: ({item, changeInfo}) => checkUpdation(item, changeInfo),
mutationKey: ['cart'],
onSuccess: () => {
console.log('quantity updated');
queryClient.invalidateQueries({
queryKey: ['cart'],
})
},
onError: () => {
// alert('Quantity can\'t update for now. Try again later ')
console.log('quantity not updated');
}
})
return {updateQuantity, updatingQuantity}
}
below are the cartItems and cartItem components .
import Button from "../../ui/Button"
import CartItem from "./CartItem"
import useCart from "./useCart"
import BackButton from "../../ui/BackButton"
const CartItems = () => {
const {cartItems, loadingCart} = useCart()
if(loadingCart) return <h1 className="text-stone-400">Loading Cart Items... </h1>
const totalCartAmount = cartItems.reduce((acc, curr) => acc + curr.total_price, 0);
return (
<section className="w-full h-full py-[3rem] px-[1rem] border-2">
<div className="cart-wrapper w-[90%] mx-auto rounded-md bg-white py-[3rem] px-[1rem] space-y-10 ">
<BackButton />
<h1 className="text-center border-b pb-4">Your Cart</h1>
<ul className="flex flex-col gap-y-8 ">
{cartItems.map(item => <CartItem key={item?.id} item={item} />)}
</ul>
<div className=" grid justify-items-end gap-y-4 py-2 px-4">
<p className=" text-xl">Total: $<strong className="strong">{totalCartAmount}</strong></p>
<Button
variation='primary'
width='fit'
>
Proceed to checkout
</Button>
</div>
</div>
</section>
)
}
export default CartItems
finally here is cartItem component
import Button from "../../ui/Button"
import { useQuantity } from "./useQuantity"
const CartItem = ({item}) => {
const {updateQuantity, updatingQuantity} = useQuantity()
return (
<li className="cart-item bg-stone-100 px-3 py-2 flex md:items-center max-md:items-start md:gap-x-4 max-md:flex-col rounded-sm max-md:gap-y-1">
<figure className="md:w-[200px] max-md:w-full md:h-[200px] max-h-[220px] h-[210px] rounded-md ">
<img src={item?.image} className="w-[100%] h-[100%] aspect-square rounded-md" alt="" />
</figure>
<div className="flex-grow w-full">
<div className="flex items-center justify-between md:pr-[2rem]">
<div className="space-y-1">
<strong className="strong ">{item?.name}</strong>
<p className="text-sm">Delivery at: 24th July</p>
</div>
<div>
<strong className="strong ">Product Price</strong>
<p className="text-center">${item?.price}</p>
</div>
<div className="flex items-center md:gap-x-4 ">
<p className="space-x-2">
<Button
width='fit'
variation='small'
onClick={() => updateQuantity({item, changeInfo:'decrease'})}
disabled={updatingQuantity}
>-</Button>
<span className="border-2 border-stone-200 text-lg text-stone-500 py-1 px-4">{item?.quantity}</span>
<Button
width='fit'
variation='small'
onClick={() => updateQuantity({item, changeInfo:'increase'})}
disabled={updatingQuantity}
>+
</Button>
</p>
<div>
<strong className="strong">Total Price:</strong>
<p>$ <strong className="text-yellow-700 text-xl">{`${item?.total_price}`}</strong></p>
</div>
</div>
</div>
</div>
</li>
)
}
export default CartItem
After mutations data should be re-fetched and my compenents will be re-rendered. even data updates on supabase table on every mutation. if i do hard reload to the page, then ui changes every time not automatically on mutation . i've tried queryClient.invalidateQueries , queryClient.refetchQueries.
not getting required results . please resolve my issue