State Management
The @vue-storefront/next and @vue-storefront/nuxt packages provide global state management out of the box. Under the hood, Next.js uses Zustand and Nuxt uses Pinia.
The state stores core data such as:
- customer
- cart
- currently selected currency
- available currencies
- currently selected locale
- available locales
Both packages expose hooks (Next.js) or composables (Nuxt) for reading and updating this data across your application.
Installation
To use the State Manager within Next.js, you need to have the @vue-storefront/next package installed. This step is already done if you have followed the Getting Started. If not, you'll find installation instructions there.
Usage
If you followed the Getting Started guide, your sdk/alokai-context.tsx already exports state hooks alongside AlokaiProvider and useSdk. These hooks are returned by createAlokaiContext and follow React's useState pattern — each returns a [value, setter] tuple.
Available hooks
| Hook | State | Type |
|---|---|---|
useSfCartState | Current cart | SfCart | null |
useSfCustomerState | Logged-in customer | SfCustomer | null |
useSfCurrencyState | Selected currency | SfCurrency |
useSfCurrenciesState | Available currencies | SfCurrency[] |
useSfLocaleState | Selected locale | SfLocale |
useSfLocalesState | Available locales | SfLocale[] |
The types come from the SfContract generic you pass to createAlokaiContext<Sdk, SfContract>(). This contract tells the state hooks which types your middleware uses for cart, customer, currency, and locale. Since those types can be customized in your middleware, the contract keeps everything in sync.
Initial data
The AlokaiProvider accepts an initialData prop to hydrate state on the first render. This avoids a flash of empty state during SSR. Pass currencies, currency, locale, and locales:
<AlokaiProvider
initialData={{
currencies: ["USD", "EUR"],
currency: "USD",
locale: "en",
locales: ["en", "de"],
}}
sdk={getSdk({ getLocale: () => locale })}
>
{children}
</AlokaiProvider>
In the Alokai Storefront, this data is fetched on the server in app/[locale]/layout.tsx and passed down to the client Providers component as props. See the Getting Started guide for the full setup.
Reading state
Use the hooks in any client component to read global state. You only need the value (first element of the tuple):
"use client";
import { useSfCartState, useSfCurrencyState } from "@/sdk/alokai-context";
export function CartSummary() {
const [cart] = useSfCartState();
const [currency] = useSfCurrencyState();
return (
<div>
<p>Items in cart: {cart?.totalItems ?? 0}</p>
<p>Currency: {currency}</p>
</div>
);
}
Updating state
Use the setter (second element of the tuple) to update state. For example, changing the selected currency:
"use client";
import { useRouter } from "next/navigation";
import { useSfCurrencyState } from "@/sdk/alokai-context";
export function CurrencySelector() {
const router = useRouter();
const [currency, setCurrency] = useSfCurrencyState();
return (
<select
onChange={(e) => {
setCurrency(e.target.value);
router.refresh();
}}
value={currency}
>
<option value="USD">USD</option>
<option value="EUR">EUR</option>
</select>
);
}
In the Alokai Storefront, cart and customer state is synced automatically. A StateObserver component subscribes to TanStack Query observers and calls setCart / setCustomer whenever the cached data changes — so you don't need to manually sync query results into state. This component is already wired up in the storefront, so no extra setup is required on your end.