A collection of react-query hooks for fetching, caching, and mutating data from the Salesforce B2C Commerce API (SCAPI).
npm install @salesforce/commerce-sdk-react @tanstack/react-query
To integrate this library with your PWA Kit application you can use the CommerceApiProvider
directly assuming that you use the withReactQuery
higher order component to wrap your AppConfig
component. Below is a snippet of how this is accomplished.
// app/components/_app-config/index.jsx
import {CommerceApiProvider} from '@salesforce/commerce-sdk-react'
import {withReactQuery} from '@salesforce/pwa-kit-react-sdk/ssr/universal/components/with-react-query'
const AppConfig = ({children}) => {
return (
<CommerceApiProvider
clientId="12345678-1234-1234-1234-123412341234"
organizationId="f_ecom_aaaa_001"
proxy="localhost:3000/mobify/proxy/api"
redirectURI="localhost:3000/callback"
siteId="RefArch"
shortCode="12345678"
locale="en-US"
currency="USD"
>
{children}
</CommerceApiProvider>
)
}
// Set configuration options for react query.
// NOTE: This configuration will be used both on the server-side and client-side.
const options = {
queryClientConfig: {
defaultOptions: {
queries: {
retry: false
},
mutations: {
retry: false
}
}
}
}
export default withReactQuery(AppConfig, options)
You can use this library in any React application by creating a new QueryClient and wrap your application with QueryClientProvider
. For example:
import {CommerceApiProvider} from '@salesforce/commerce-sdk-react'
import {QueryClient, QueryClientProvider} from '@tanstack/react-query'
const App = ({children}) => {
const queryClient = new QueryClient()
return (
<QueryClientProvider client={queryClient}>
<CommerceApiProvider
clientId="12345678-1234-1234-1234-123412341234"
organizationId="f_ecom_aaaa_001"
proxy="localhost:3000/mobify/proxy/api"
redirectURI="localhost:3000/callback"
siteId="RefArch"
shortCode="12345678"
locale="en-US"
currency="USD"
>
{children}
</CommerceApiProvider>
</QueryClientProvider>
)
}
export default App
💡 This section assumes you have read and completed the Authorization for Shopper APIs guide.
To help reduce boilerplate code for managing shopper authentication, by default, this library automatically initializes shopper session and manages the tokens for developers. Currently, the library supports the Public Client login flow.
On CommerceApiProvider
mount, the provider initializes shopper session by initiating the SLAS Public Client login flow. The tokens are stored/managed/refreshed by the library.
While the library is fetching/refreshing the access token, the network requests will queue up until there is a valid access token.
To leverage the managed shopper authentication feature, use the useAuthHelper
hook for shopper login.
Example:
import {AuthHelpers, useAuthHelper} from '@salesforce/commerce-sdk-react'
const Example = () => {
const register = useAuthHelper(AuthHelpers.Register)
const login = useAuthHelper(AuthHelpers.LoginRegisteredUserB2C)
const logout = useAuthHelper(AuthHelpers.LogOut)
return <button onClick={() => {
login.mutate({username: 'kevin', password: 'pa$$word'})
}}>
}
You have the option of handling shopper authentication externally, by providing a SLAS access token. This is useful if you plan on using this library in an application where the authentication mechanism is different.
const MyComponent = ({children}) => {
return (
<CommerceApiProvider fetchedToken="xxxxxxxxxxxx">
{children}
</CommerceApiProvider>
)
}
The majority of hooks provided in this library are built on top of the useQuery and the useMutation hook from react-query. React-query provides a declarative way for fetching and updating data. This library takes advantage of the features provided by react-query and combine with the commerce-sdk-isomorphic API client to create a collection of hooks to simplify data fetching for SCAPI.
The hooks can be categorized into Query hooks and Mutation hooks.
The query hooks correspond to the http GET endpoints from the SCAPI. The query hooks follow the signature pattern:
use<EntityName>(CommerceClientOptions, ReactQueryOptions)
Both the required and optional parameters for the underlying commerce-sdk-isomorphic
call is passed as the first parameter:
import {useProduct} from '@salesforce/commerce-sdk-react'
const Example = () => {
const query = useProduct({
parameters: {
id: '25592770M',
locale: 'en-US'
}
})
return <>
<p>isLoading: {query.isLoading}</p>
<p>name: {query.data?.name}</p>
</>
}
The second parameter is the react-query query options, for more detail, read useQuery reference.
import {useBasket} from '@salesforce/commerce-sdk-react'
const onServer = typeof window === undefined
const Example = ({basketId}) => {
const query = useBasket({
parameters: {
basketId: basketId
},
}, {
// A common use case for `enabled` is
// to conditionally fetch based on environment
enabled: !onServer && basketId
})
}
The query hooks correspond to the http POST, PUT, PATCH, DELETE endpoints from the SCAPI. The mutation hooks follow the signature pattern:
use<ApiName>Mutation(EndpointName)
For example, the ShopperBaskets API has a number of endpoints, one of them being the addItemToBasket endpoint (POST /baskets/{basketId}/items
).
import {useShopperBasketsMutation} from '@salesforce/commerce-sdk-react'
const Example = ({basketId}) => {
// Typescript IDE intellisense for available options
const addItemToBasket = useShopperBasketsMutation('addItemToBasket')
return <button onClick={() => addItemToBasket.mutate({
parameters: {
basketId
},
body: {
productId: '25592770M',
price: 55,
quantity: 1
}
})} />
}
You could also import the mutation options as a constant like:
import {useShopperBasketsMutation, ShopperBasketsMutations} from '@salesforce/commerce-sdk-react'
const Example = ({basketId}) => {
// this works
const addItemToBasket = useShopperBasketsMutation('addItemToBasket')
// this also works
const addItemToBasket = useShopperBasketsMutation(ShopperBasketsMutations.AddItemToBasket)
return ...
}
Since mutations changes data on the server, the cache entries that are potentially affected by the mutation is automatically invalidated.
For example, an addItemToBasket
mutation automatically update useBasket
and useCustomerBaskets
query cache, because the mutation result contains the information for the updated basket. In other cases, when the mutation response do not have the updated data, the library will invalidate the cache and trigger a re-fetch. For the DELETE endpoints, the library removes the cache entries on successful mutations.
💡 Debugging hint: install and include @tanstack/react-query-devtools
in your React app to see the queries (inspect the query states and cache keys).
Besides the collection of query hooks and mutation hooks, here are some ultility hooks to help you interact with SCAPI.
useCommerceApi()
This hook returns a set of SCAPI clients, which are already initialized using the configurations passed to the provider. Note: this hook doesn't automatically include auth headers.
import {useCommerceApi, useAccessToken} from '@salesforce/commerce-sdk-react'
const Example = () => {
const api = useCommerceApi()
const {getTokenWhenReady} = useAccessToken()
const fetchProducts = async () => {
const token = await getTokenWhenReady()
const products = await api.shopperProducts.getProducts({
parameters: {ids: ids.join(',')},
headers: {
Authorization: `Bearer ${token}`
}
})
return products
}
}
useAccessToken()
useAccessToken() => {token: String, getTokenWhenReady: Promise}
This ultility hook give access to the managed SLAS access token.
useCustomerId()
useCustomerId() => null | string
useCustomerType()
useCustomerId() => null | 'guest' | 'registered'
useEncUserId()
useEncUserId() => null | string
useUsid()
useUsid() => null | string