* docs: added features and guides overview page * added image * added version 2 * added version 3 * added version 4 * docs: implemented new color scheme * docs: redesigned sidebar (#3193) * docs: redesigned navbar for restructure (#3199) * docs: redesigned footer (#3209) * docs: redesigned cards (#3230) * docs: redesigned admonitions (#3231) * docs: redesign announcement bar (#3236) * docs: redesigned large cards (#3239) * docs: redesigned code blocks (#3253) * docs: redesigned search modal and page (#3264) * docs: redesigned doc footer (#3268) * docs: added new sidebars + refactored css and assets (#3279) * docs: redesigned api reference sidebar * docs: refactored css * docs: added code tabs transition * docs: added new sidebars * removed unused assets * remove unusued assets * Fix deploy errors * fix incorrect link * docs: fixed code responsivity + missing icons (#3283) * docs: changed icons (#3296) * docs: design fixes to the sidebar (#3297) * redesign fixes * docs: small design fixes * docs: several design fixes after restructure (#3299) * docs: bordered icon fixes * docs: desgin fixes * fixes to code blocks and sidebar scroll * design adjustments * docs: restructured homepage (#3305) * docs: restructured homepage * design fixes * fixed core concepts icon * docs: added core concepts page (#3318) * docs: restructured homepage * design fixes * docs: added core concepts page * changed text of different components * docs: added architecture link * added missing prop for user guide * docs: added regions overview page (#3327) * docs: added regions overview * moved region pages to new structure * docs: fixed description of regions architecture page * small changes * small fix * docs: added customers overview page (#3331) * docs: added regions overview * moved region pages to new structure * docs: fixed description of regions architecture page * small changes * small fix * docs: added customers overview page * fix link * resolve link issues * docs: updated regions architecture image * docs: second-iteration fixes (#3347) * docs: redesigned document * design fixes * docs: added products overview page (#3354) * docs: added carts overview page (#3363) * docs: added orders overview (#3364) * docs: added orders overview * added links in overview * docs: added vercel redirects * docs: added soon badge for cards (#3389) * docs: resolved feedback changes + organized troubleshooting pages (#3409) * docs: resolved feedback changes * added extra line * docs: changed icons for restructure (#3421) * docs: added taxes overview page (#3422) * docs: added taxes overview page * docs: fix sidebar label * added link to taxes overview page * fixed link * docs: fixed sidebar scroll (#3429) * docs: added discounts overview (#3432) * docs: added discounts overview * fixed links * docs: added gift cards overview (#3433) * docs: added price lists overview page (#3440) * docs: added price lists overview page * fixed links * docs: added sales channels overview page (#3441) * docs: added sales overview page * fixed links * docs: added users overview (#3443) * docs: fixed sidebar border height (#3444) * docs: fixed sidebar border height * fixed svg markup * docs: added possible solutions to feedback component (#3449) * docs: added several overview pages + restructured files (#3463) * docs: added several overview pages * fixed links * docs: added feature flags + PAK overview pages (#3464) * docs: added feature flags + PAK overview pages * fixed links * fix link * fix link * fixed links colors * docs: added strategies overview page (#3468) * docs: automated upgrade guide (#3470) * docs: automated upgrade guide * fixed vercel redirect * docs: restructured files in docs codebase (#3475) * docs: restructured files * docs: fixed eslint exception * docs: finished restructure loose-ends (#3493) * fixed uses of backend * docs: finished loose ends * eslint fixes * fixed links * merged master * added update instructions for v1.7.12
19 KiB
description
| description |
|---|
| Learn how to install Medusa React in a React storefront. Medusa React is a React library that provides a set of utilities and hooks for interactive with the Medusa backend. |
Medusa React
Medusa React is a React library that provides a set of utilities and hooks for interacting seamlessly with the Medusa backend. It can be used to build custom React-based storefronts or admin dashboards.
:::tip
Alternatively, you can use Medusa’s JS Client or the REST APIs.
:::
Installation
In the directory holding your React-based storefront or admin dashboard, run the following command to install Medusa React:
npm install medusa-react @tanstack/react-query @medusajs/medusa
In addition to the medusa-react library, you need the following libraries:
1. @tanstack/react-query: medusa-react is built on top of Tanstack Query. You’ll learn later in this reference how you can use Mutations and Queries with Medusa React.
:::note
Versions of Medusa React prior to v4.0.2 used React Query v3 instead of Tanstack Query. Check out [this upgrade guide] to learn how you can update your storefront.
:::
2. @medusajs/medusa: The core Medusa package. This is used to import types used by Medusa React and while developing with it.
:::info
Part of the Medusa roadmap is to move the types into a separate package, removing the need to install the core Medusa package in your storefront or admin dashboard. You can check other items on our roadmap in GitHub Discussions.
:::
Usage
To use the hooks exposed by Medusa React, you need to include the MedusaProvider somewhere up in your component tree.
The MedusaProvider requires two props:
baseUrl: The URL to your Medusa backendqueryClientProviderProps: An object used to set the Tanstack Query client. The object requires aclientproperty, which should be an instance of QueryClient.
For example:
import { MedusaProvider } from "medusa-react"
import Storefront from "./Storefront"
import { QueryClient } from "@tanstack/react-query"
import React from "react"
const queryClient = new QueryClient()
const App = () => {
return (
<MedusaProvider
queryClientProviderProps={{ client: queryClient }}
baseUrl="http://localhost:9000"
>
<Storefront />
</MedusaProvider>
)
}
export default App
In the example above, you wrap the Storefront component with the MedusaProvider. Storefront is assumed to be the top-level component of your storefront, but you can place MedusaProvider at any point in your tree. Only children of MedusaProvider can benefit from its hooks.
The Storefront component and its child components can now use hooks exposed by Medusa React.
MedusaProvider Optional Props
You can also pass the following props to Medusa Provider:
| Props | Default | Description |
|---|---|---|
apiKey |
'' |
Optional API key used for authenticating admin requests. |
publishableApiKey |
'' |
Optional publishable API key used for storefront requests. |
Queries
To fetch data from the Medusa backend (in other words, perform GET requests), you can use Queries. Query hooks simply wrap around Tanstack Query's useQuery hook to fetch data from your medusa backend.
For example, to fetch products from your Medusa backend:
import { Product } from "@medusajs/medusa"
import { useProducts } from "medusa-react"
const Products = () => {
const { products, isLoading } = useProducts()
return isLoading ? (
<div>
Loading...
</div>
) : (
<ul>
{products?.map((product: Product) => (
<li key={product.id}>
{product.title}
</li>
))}
</ul>
)
}
export default Products
In the example above, you import the useProducts hook from medusa-react. This hook, and every other query hook exposed by medusa-react, returns everything that useQuery returns in Tanstack Query, except for the data field.
Instead of the data field, the response data is flattened and is part of the hooks’ returned fields. In the example above, the List Products endpoint returns a products array. So, useProducts returns a products array along with other fields returned by useQuery.
If the request accepts any parameters, they can be passed as parameters to the mutate request. For example:
const { products } = useProducts({
expand: "variants",
})
You can learn more about using queries in Tanstack Query’s documentation.
Mutations
To create, update, or delete data on the Medusa backend (in other words, perform POST, PUT, and DELETE requests), you can use Mutations. Mutation hooks wrap around Tanstack Query's useMutation to mutate data on your medusa backend.
For example, to create a cart:
import { useCreateCart } from "medusa-react"
const Cart = () => {
const createCart = useCreateCart()
const handleClick = () => {
createCart.mutate({}) // create an empty cart
}
return (
<div>
{createCart.isLoading && <div>Loading...</div>}
{!createCart.data?.cart && (
<button onClick={handleClick}>
Create cart
</button>
)}
{createCart.data?.cart?.id && (
<div>Cart ID: {createCart.data?.cart.id}</div>
)}
</div>
)
}
export default Cart
In the example above, you import the useCreateCart hook from medusa-react. This hook, and every other mutation hook exposed by medusa-react, returns everything that useMutation returns. You can also pass the same options you would pass to useMutation to mutation hooks exposed by medusa-react.
To create a cart, you call the createCart.mutate method. In the underlying logic, this method sends a POST request to the Medusa backend to create a cart.
If the request accepts any parameters, they can be passed as parameters to the mutate request. For example:
createCart.mutate({
region_id,
})
Once the cart is created, you can access it in the data field returned by the mutation hook. This field includes all data returned in the response.
:::note
The example above does not store in the browser the ID of the cart created, so the cart’s data will be gone on release. You would have to do that using the browser’s Local Storage.
:::
Instead of using mutate, you can use mutateAsync to receive a Promise that resolves on success or throws on error.
Learn more about how you can use mutations in Tanstack Query’s documentation.
Utilities
medusa-react exposes a set of utility functions that are mainly used to retrieve or format the price of a product variant.
formatVariantPrice
This utility function can be used to compute the price of a variant for a region and retrieve the formatted amount. For example, $20.00.
It accepts an object with the following properties:
variant: A variant object retrieved from the Medusa backend. It should mainly include thepricesarray in the object.region: A region object retrieved from the Medusa backend.includeTaxes: (optional) A boolean value that indicates whether the computed price should include taxes or not. The default value istrue.minimumFractionDigits: (optional) The minimum number of fraction digits to use when formatting the price. This is passed as an option toIntl.NumberFormatin the underlying layer. You can learn more about this method’s options in MDN’s documentation.maximumFractionDigits: (optional) The maximum number of fraction digits to use when formatting the price. This is passed as an option toIntl.NumberFormatwhich is used within the utility method. You can learn more about this method’s options in MDN’s documentation.locale: (optional) A string with a BCP 47 language tag. The default value isen-US. This is passed as a first parameter toIntl.NumberFormatwhich is used within the utility method. You can learn more about this method’s parameters in MDN’s documentation.
For example:
import { formatVariantPrice } from "medusa-react"
import { Product, ProductVariant } from "@medusajs/medusa"
const Products = () => {
// ...
return (
<ul>
{products?.map((product: Product) => (
<li key={product.id}>
{product.title}
<ul>
{product.variants.map((variant: ProductVariant) => (
<li key={variant.id}>
{formatVariantPrice({
variant,
region, // should be retrieved earlier
})}
</li>
))}
</ul>
</li>
))}
</ul>
)
}
computeVariantPrice
This utility function can be used to compute the price of a variant for a region and retrieve the amount without formatting. For example, 20. This method is used by formatVariantPrice before applying the price formatting.
It accepts an object with the following properties:
variant: A variant object retrieved from the Medusa backend. It should mainly include thepricesarray in the variant.region: A region object retrieved from the Medusa backend.includeTaxes: (optional) A boolean value that indicates whether the computed price should include taxes or not. The default value istrue.
For example:
import { computeVariantPrice } from "medusa-react"
import { Product, ProductVariant } from "@medusajs/medusa"
const Products = () => {
// ...
return (
<ul>
{products?.map((product: Product) => (
<li key={product.id}>
{product.title}
<ul>
{product.variants.map((variant: ProductVariant) => (
<li key={variant.id}>
{computeVariantPrice({
variant,
region, // should be retrieved earlier
})}
</li>
))}
</ul>
</li>
))}
</ul>
)
}
formatAmount
This utility function can be used to compute the price of an amount for a region and retrieve the formatted amount. For example, $20.00.
The main difference between this utility function and formatVariantPrice is that you don’t need to pass a complete variant object. This can be used with any number.
It accepts an object with the following properties:
amount: A number that should be used for computation.region: A region object retrieved from the Medusa backend.includeTaxes: (optional) A boolean value that indicates whether the computed price should include taxes or not. The default value istrue.minimumFractionDigits: (optional) The minimum number of fraction digits to use when formatting the price. This is passed as an option toIntl.NumberFormatin the underlying layer. You can learn more about this method’s options in MDN’s documentation.maximumFractionDigits: (optional) The maximum number of fraction digits to use when formatting the price. This is passed as an option toIntl.NumberFormatwhich is used within the utility method. You can learn more about this method’s options in MDN’s documentation.locale: (optional) A string with a BCP 47 language tag. The default value isen-US. This is passed as a first parameter toIntl.NumberFormatwhich is used within the utility method. You can learn more about this method’s parameters in MDN’s documentation.
For example:
import { formatAmount } from "medusa-react"
const MyComponent = () => {
// ...
return (
<div>
{formatAmount({
amount,
region, // should be retrieved earlier
})}
</div>
)
}
computeAmount
This utility function can be used to compute the price of an amount for a region and retrieve the amount without formatting. For example, 20. This method is used by formatAmount before applying the price formatting.
The main difference between this utility function and computeVariantPrice is that you don’t need to pass a complete variant object. This can be used with any number.
It accepts an object with the following properties:
amount: A number that should be used for computation.region: A region object retrieved from the Medusa backend.includeTaxes: (optional) A boolean value that indicates whether the computed price should include taxes or not. The default value istrue.
For example:
import { computeAmount } from "medusa-react"
const MyComponent = () => {
// ...
return (
<div>
{computeAmount({
amount,
region, // should be retrieved earlier
})}
</div>
)
}
Content Providers
:::info
This is an experimental feature.
:::
To facilitate building custom storefronts, medusa-react also exposes a CartProvider and a SessionCartProvider.
CartProvider
CartProvider makes use of some of the hooks already exposed by medusa-react to perform cart operations on the Medusa backend. You can use it to create a cart, start the checkout flow, authorize payment sessions, and so on.
It also manages one single global piece of state which represents a cart, exactly like the one created on your medusa backend.
To use CartProvider, you first have to insert it somewhere in your component tree below the MedusaProvider.
For example:
import { CartProvider, MedusaProvider } from "medusa-react"
import Storefront from "./Storefront"
import { QueryClient } from "@tanstack/react-query"
import React from "react"
const queryClient = new QueryClient()
function App() {
return (
<MedusaProvider
queryClientProviderProps={{ client: queryClient }}
baseUrl="http://localhost:9000"
>
<CartProvider>
<Storefront />
</CartProvider>
</MedusaProvider>
)
}
export default App
Then, in any of the child components, you can use the useCart hook exposed by medusa-react to get access to cart operations and data.
The useCart hook returns an object with the following properties:
cart: A state variable holding the cart object. This is set if thecreateCartmutation is executed or ifsetCartis manually used.setCart: A state function used to set the cart object.totalItems: The number of items in the cart.createCart: A mutation used to create a cart.updateCart: A mutation used to update a cart’s details such as region, customer email, shipping address, and more.startCheckout: A mutation used to initialize payment sessions during checkout.pay: A mutation used to select a payment provider during checkout.addShippingMethod: A mutation used to add a shipping method to the cart during checkout.completeCheckout: A mutation used to complete the cart and place the order.
For example:
import * as React from "react"
import { useCart } from "medusa-react"
const Cart = () => {
const handleClick = () => {
createCart.mutate({}) // create an empty cart
}
const { cart, createCart } = useCart()
return (
<div>
{createCart.isLoading && <div>Loading...</div>}
{!cart?.id && (
<button onClick={handleClick}>
Create cart
</button>
)}
{cart?.id && (
<div>Cart ID: {cart.id}</div>
)}
</div>
)
}
export default Cart
In the example above, you retrieve the createCart mutation and cart state object using the useCart hook. If the cart is not set, a button is shown. When the button is clicked, the createCart mutation is executed, which interacts with the backend and creates a new cart.
After the cart is created, the cart state variable is set and its ID is shown instead of the button.
:::note
The example above does not store in the browser the ID of the cart created, so the cart’s data will be gone on release. You would have to do that using the browser’s Local Storage.
:::
SessionProvider
Unlike the CartProvider, SessionProvider never interacts with the Medusa backend. It can be used to implement the user experience related to managing a cart’s items. Its state variables are JavaScript objects living in the browser, but are in no way communicated with the backend.
You can use the SessionProvider as a lightweight client-side cart functionality. It’s not stored in any database or on the Medusa backend.
To use SessionProvider, you first have to insert it somewhere in your component tree below the MedusaProvider.
For example:
import { SessionProvider, MedusaProvider } from "medusa-react"
import Storefront from "./Storefront"
import { QueryClient } from "@tanstack/react-query"
import React from "react"
const queryClient = new QueryClient()
const App = () => {
return (
<MedusaProvider
queryClientProviderProps={{ client: queryClient }}
baseUrl="http://localhost:9000"
>
<SessionProvider>
<Storefront />
</SessionProvider>
</MedusaProvider>
)
}
export default App
Then, in any of the child components, you can use the useSessionHook hook exposed by medusa-react to get access to client-side cart item functionalities.
For example:
const Products = () => {
const { addItem } = useSessionCart()
// ...
function addToCart(variant: ProductVariant) {
addItem({
variant: variant,
quantity: 1,
})
}
}