Create Cart Context in the Storefront

Share cart state across React components.

On this page

In this guide, you'll learn how to share cart state in a storefront.

Do not create a client CartProvider that calls the SDK in useEffect and stores the cart ID in localStorage.

On Next.js:

  1. Persist the cart ID in the _aiminaabee_cart_id httpOnly cookie.
  2. Create or load the cart in src/lib/data/cart.ts (getOrSetCart, retrieveCart).
  3. Call those functions from pages and server actions. Pass storeCode and the URL countryCode separately.
  4. After mutations, revalidateTag for carts (and fulfillment when shipping options can change).

See Build a Next.js Storefront and Create Cart.

A small client hook is fine for UI-only cart drawers. It should call server actions, not sdk.store.cart directly.


SPA: Cart Context Provider

If you're building a client-rendered SPA (not App Router), a React context can hold the current cart so product pages can add items without prop drilling.

The provider should:

  • Resolve the customer's region first.
  • Create a cart if none exists, or retrieve it by ID.
  • Persist the cart ID the same way the rest of the SPA does (cookie or memory). Prefer a cookie over localStorage so you can later move to SSR.

tsx

tsxCopy
"use client"
import {
createContext,
useContext,
useEffect,
useState,
} from "react"
import { HttpTypes } from "@aiminaabeejs/types"
import { useRegion } from "./region"
import { sdk } from "@/lib/sdk"
type CartContextType = {
cart?: HttpTypes.StoreCart
setCart: React.Dispatch<
React.SetStateAction<HttpTypes.StoreCart | undefined>
>
refreshCart: () => void
}
const CartContext = createContext<CartContextType | null>(null)
export const CartProvider = ({ children }: { children: React.ReactNode }) => {
const [cart, setCart] = useState<HttpTypes.StoreCart>()
const { region } = useRegion()
useEffect(() => {
if (cart || !region) {
return
}
const cartId = window.__CART_ID__ as string | undefined
if (!cartId) {
sdk.store.cart.create(storeCode, {
region_id: region.id,
})
.then(({ cart: dataCart }) => {
setCart(dataCart)
})
} else {
sdk.store.cart.retrieve(storeCode, cartId)
.then(({ cart: dataCart }) => {
setCart(dataCart)
})
}
}, [cart, region])
const refreshCart = () => {
setCart(undefined)
}
return (
<CartContext.Provider value={{ cart, setCart, refreshCart }}>
{children}
</CartContext.Provider>
)
}
export const useCart = () => {
const context = useContext(CartContext)
if (!context) {
throw new Error("useCart must be used within a CartProvider")
}
return context
}

Wrap the tree with RegionProvider outside CartProvider. Use refreshCart after login, logout, or placing an order.

Tip: Add helpers for line items and region updates from: