Customer Context in the Storefront

Share customer state across React components.

On this page

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

Do not keep the customer in a client context that fetches in useEffect.

On Next.js, retrieveCustomer(storeCode) in src/lib/data/customer.ts reads _aiminaabee_jwt and returns null when there is no token. Call it from layouts and account pages. After login or signup, setAuthToken and transferCart. After signout, clear the token and cart cookies.

See Login and Build a Next.js Storefront.

A client hook is fine for UI (avatar menu). It should call server actions or receive the customer from a server parent.


SPA: Customer Context Provider

Throughout your storefront, you'll need to access the logged-in customer to perform different actions, such as associating it with a cart.

So, if your storefront is React-based, you can create a customer context and add it at the top of your components tree. Then, you can access the logged-in customer anywhere in your storefront.


Create Customer Context Provider

For example, create the following file that exports a CustomerProvider component and a useCustomer hook:

Tip: Learn how to install and configure the JS SDK in the Getting started guide.

tsx

tsxCopy
"use client" // include with Next.js 13+
import {
createContext,
useContext,
useEffect,
useState,
} from "react"
import { HttpTypes } from "@aiminaabeejs/types"
import { sdk } from "@/lib/sdk"
type CustomerContextType = {
customer: HttpTypes.StoreCustomer | undefined
setCustomer: React.Dispatch<
React.SetStateAction<HttpTypes.StoreCustomer | undefined>
>
}
const CustomerContext = createContext<CustomerContextType | null>(null)
type CustomerProviderProps = {
children: React.ReactNode
}
export const CustomerProvider = ({
children,
}: CustomerProviderProps) => {
const [customer, setCustomer] = useState<
HttpTypes.StoreCustomer
>()
useEffect(() => {
if (customer) {
return
}
sdk.store.customer.retrieve("us")
.then(({ customer }) => {
setCustomer(customer)
})
.catch((err) => {
// customer isn't logged in
})
}, [])
return (
<CustomerContext.Provider value={{
customer,
setCustomer,
}}>
{children}
</CustomerContext.Provider>
)
}
export const useCustomer = () => {
const context = useContext(CustomerContext)
if (!context) {
throw new Error("useCustomer must be used within a CustomerProvider")
}
return context
}

The CustomerProvider handles retrieving the authenticated customer from the Aiminaabee application. This assumes that the JS SDK is already configured for authentication and the customer's authentication token was set as explained in the Login in Storefront and Third-Party Login guides.

The useCustomer hook returns the value of the CustomerContext. Child components of CustomerProvider use this hook to access customer or setCustomer.


Use CustomerProvider in Component Tree

To use the customer context's value, add the CustomerProvider high in your component tree.

For example, if you're using Next.js, add it to the app/layout.tsx or src/app/layout.tsx file:

tsx

tsxCopy
import type { Metadata } from "next"
import { Inter } from "next/font/google"
import "./globals.css"
import { CartProvider } from "@/providers/cart"
import { RegionProvider } from "@/providers/region"
import { CustomerProvider } from "@/providers/customer"
const inter = Inter({ subsets: ["latin"] })
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
}
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body className={inter.className}>
<RegionProvider>
<CustomerProvider>
{/* Other providers... */}
<CartProvider>
{children}
</CartProvider>
</CustomerProvider>
</RegionProvider>
</body>
</html>
)
}

Use useCustomer Hook

Now, you can use the useCustomer hook in child components of CustomerProvider.

For example:

tsx

tsxCopy
"use client" // include with Next.js 13+
// ...
import { useCustomer } from "@/providers/customer"
export default function Profile() {
const { customer } = useCustomer()
// ...
}