Loading…
Loading…
Standalone cart mutations hook for external state management without SessionProvider dependency.
A standalone hook for executing cart mutations without requiring a SessionProvider. Ideal for situations where you manage cart state externally or need direct control over the cart and update callback.
useCartMutationsWithCart provides the same cart mutation capabilities as useCartMutations, but accepts the cart and update callback directly as parameters instead of consuming them from a session context.
Use this hook when:
import { useCartMutationsWithCart } from '@woographql/react-hooks'; import { useMyCartStore } from './cartStore'; function AddToCartButton({ productId }: { productId: number }) { const { cart, updateCart } = useMyCartStore(); const { quantityFound, mutate, fetching } = useCartMutationsWithCart( { productId }, cart, updateCart ); const handleClick = () => { if (quantityFound) { mutate('removeItemsFromCart', {}); } else { mutate('addToCart', { quantity: 1 }); } }; return ( <button onClick={handleClick} disabled={fetching}> {fetching ? 'Loading...' : quantityFound ? 'Remove' : 'Add to Cart'} </button> ); }
function useCartMutationsWithCart( product: { productId: number; variationId?: number; variation?: { attributeName: string; attributeValue: string }[]; extraData?: string; }, cart: Cart | null, updateCart: (action: CartAction) => Promise<Cart | null> ): { fetching: boolean; quantityFound: number; mutate: (mutation?: string, input: CartMutationInput) => Promise<Cart | null | undefined>; };
| Parameter | Type | Description |
|---|---|---|
product.productId | number | The product's database ID |
product.variationId | number | Optional variation ID for variable products |
product.variation | array | Optional variation attributes |
product.extraData | string | Optional JSON string for custom cart item data |
cart | Cart | null | The current cart state |
updateCart | function | Callback to execute cart mutations |
| Property | Type | Description |
|---|---|---|
fetching | boolean | True when a cart operation is in progress |
quantityFound | number | Quantity of this product currently in cart |
mutate | function | Execute a cart mutation |
const { mutate } = useCartMutationsWithCart({ productId: 123 }, cart, updateCart); // Simple product mutate('addToCart', { quantity: 2 }); // Variable product const { mutate } = useCartMutationsWithCart( { productId: 123, variationId: 456, variation: [ { attributeName: 'pa_color', attributeValue: 'blue' }, { attributeName: 'pa_size', attributeValue: 'large' }, ], }, cart, updateCart ); mutate('addToCart', { quantity: 1 });
const { quantityFound, mutate } = useCartMutationsWithCart( { productId: 123 }, cart, updateCart ); if (quantityFound) { mutate('removeItemsFromCart', {}); }
const { quantityFound, mutate } = useCartMutationsWithCart( { productId: 123 }, cart, updateCart ); if (quantityFound) { mutate('updateItemQuantities', { quantity: 5 }); }
mutate('addBundleToCart', { quantity: 1, bundleItems: [ { bundleItemId: 1, quantity: 1, optionalSelected: false }, { bundleItemId: 2, quantity: 2, optionalSelected: true }, ], });
mutate('addCompositeToCart', { configuration: [ { componentId: 'base', productId: 101, quantity: 1 }, { componentId: 'accessory', productId: 202, quantity: 1 }, ], });
import { useSelector, useDispatch } from 'react-redux'; import { useCartMutationsWithCart } from '@woographql/react-hooks'; function ProductCard({ productId }) { const dispatch = useDispatch(); const cart = useSelector((state) => state.cart); const updateCart = async (action) => { const response = await fetch('/api/cart', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(action), }); const data = await response.json(); dispatch({ type: 'SET_CART', payload: data.cart }); return data.cart; }; const { quantityFound, mutate, fetching } = useCartMutationsWithCart( { productId }, cart, updateCart ); return ( <button onClick={() => mutate('addToCart', { quantity: 1 })} disabled={fetching} > {quantityFound ? `In Cart (${quantityFound})` : 'Add to Cart'} </button> ); }
import { create } from 'zustand'; import { useCartMutationsWithCart } from '@woographql/react-hooks'; const useCartStore = create((set) => ({ cart: null, updateCart: async (action) => { const response = await fetch('/api/cart', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(action), }); const data = await response.json(); set({ cart: data.cart }); return data.cart; }, })); function CartButton({ productId }) { const { cart, updateCart } = useCartStore(); const { quantityFound, mutate } = useCartMutationsWithCart( { productId }, cart, updateCart ); return ( <button onClick={() => mutate('addToCart', { quantity: 1 })}> Add to Cart {quantityFound > 0 && `(${quantityFound})`} </button> ); }
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { useCartMutationsWithCart } from '@woographql/react-hooks'; function ProductActions({ productId }) { const queryClient = useQueryClient(); const { data: cart } = useQuery({ queryKey: ['cart'], queryFn: () => fetch('/api/cart').then((r) => r.json()), }); const cartMutation = useMutation({ mutationFn: (action) => fetch('/api/cart', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(action), }).then((r) => r.json()), onSuccess: (data) => { queryClient.setQueryData(['cart'], data.cart); }, }); const updateCart = async (action) => { const result = await cartMutation.mutateAsync(action); return result.cart; }; const { quantityFound, mutate } = useCartMutationsWithCart( { productId }, cart, updateCart ); return ( <div> <button onClick={() => mutate('addToCart', { quantity: 1 })}> Add to Cart </button> {quantityFound > 0 && ( <button onClick={() => mutate('removeItemsFromCart', {})}> Remove ({quantityFound}) </button> )} </div> ); }
The updateCart callback should execute GraphQL mutations against your GraphQL for WooCommerce backend. Here's a generic implementation:
import type { CartAction, Cart } from '@woographql/react-hooks'; const GRAPHQL_ENDPOINT = process.env.GRAPHQL_ENDPOINT; async function updateCart(action: CartAction): Promise<Cart | null> { const { mutation, input } = action; const mutations: Record<string, string> = { addToCart: ` mutation AddToCart($input: AddToCartInput!) { addToCart(input: $input) { cart { contents(first: 100) { itemCount nodes { key quantity product { node { databaseId name } } } } total } } } `, removeItemsFromCart: ` mutation RemoveItems($input: RemoveItemsFromCartInput!) { removeItemsFromCart(input: $input) { cart { contents(first: 100) { itemCount nodes { key quantity product { node { databaseId name } } } } total } } } `, updateItemQuantities: ` mutation UpdateQuantities($input: UpdateItemQuantitiesInput!) { updateItemQuantities(input: $input) { cart { contents(first: 100) { itemCount nodes { key quantity product { node { databaseId name } } } } total } } } `, }; const query = mutations[mutation]; if (!query) { throw new Error(`Unknown mutation: ${mutation}`); } const response = await fetch(GRAPHQL_ENDPOINT, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ query, variables: { input } }), }); const { data, errors } = await response.json(); if (errors) { throw new Error(errors[0].message); } // Extract cart from response (mutation name varies) const result = Object.values(data)[0] as { cart: Cart }; return result.cart; }
| Feature | useCartMutations | useCartMutationsWithCart |
|---|---|---|
| Requires SessionProvider | Yes | No |
| Cart state source | Session context | Passed as parameter |
| Loading state | From session's isExecuting() | Local fetching state |
| Best for | Apps using SessionProvider | Custom state management |