Back to Medusa

{metadata.title}

www/apps/resources/app/storefront-development/customers/context/page.mdx

2.14.24.5 KB
Original Source

export const metadata = { title: Customer Context in Storefront, }

{metadata.title}

In this guide, you'll learn how to create a customer context in your storefront.

Why Create a Customer Context?

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:

<Note title="Tip">

Learn how to install and configure the JS SDK in the JS SDK documentation.

</Note>

export const highlights = [ ["13", "customer", "Expose customer to children of the context provider."], ["14", "setCustomer", "Allow the context provider's\nchildren to change the logged-in customer."], ["25", "CustomerProvider", "The provider component to use in your component tree."], ["37", "retrieve", "Try to retrieve the customer's details,\nif the customer is authentiated."], ["56", "useCustomer", "The hook that child components of the provider use to access the customer."] ]

tsx
"use client" // include with Next.js 13+

import { 
  createContext, 
  useContext, 
  useEffect, 
  useState,
} from "react"
import { HttpTypes } from "@medusajs/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()
    .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 Medusa 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
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>
            <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
"use client" // include with Next.js 13+
// ...
import { useCustomer } from "@/providers/customer"

export default function Profile() {
  const { customer } = useCustomer()
  // ...
}