Migrate to inventory actions and useInventory hook
Overview
This is a guide on how to migrate from manually accessing the product inventory to using the new approaches available:
useInventory
hook.
useInventory
hook.The useInventory
(Shopify / BigCommerce) hook can be used to retrieve inventory data on demand.
With the useInventory
hook, we have access to the following properties:
name | type | description |
---|---|---|
availableForSale | boolean | It is used to check whether the product is available for sale. |
quantity | number | The stock quantity of a given product. |
price | number | The product's price |
useCartActions
useCartActions
The following actions are available when using the useCartActions
:
isProductAvailableForSale
getProductQuantity
Before these helpers were available you would access products within the inventory in the following way.
// Old way
import { useCartState } from 'frontend-checkout'
const { inventory } = useCartState()
if (inventory.status === 'loading') return
const variant = inventory.productVariants[variantId]
if (!variant) return
const isAvailableForSale = variant.isAvailableForSale
const quantity = variant.quantity
With the useInventory
hook, you can get this information in the following way (check the useInventory-hook-complete-example.js
tab below for a more thorough explanation):
import { useInventory } from 'frontend-checkout'
// If you are using Shopify's Storefront api
const id = 'Z2lkOi8vc2hvcGlmeS9Qcm9kdWN0Lzc4NTc5ODkzODQ=' // storefrontId - GraphQL
// If you are using Shopify's REST api
const id = 6690750136476 // externalId - REST
// By passing an id and product type, useInventory will fetch the data for given ids
const { products, status } = useInventory({ ids: [id] })
const { availableForSale, quantity, price } = products[id] || {}
import React, { useState, useEffect } from 'react'
import { useInventory } from 'frontend-checkout'
const IDLE = 'idle'
const LOADING = 'loading'
const SOLD_OUT = 'sold out'
const ERROR = 'error'
const AddToCartButton = ({
// let's assume storefrontId is coming via props
// from parent component, say ProductBox
storefrontId,
}) => {
// state to deal with button state
const [buttonState, setButtonState] = useState(storefrontId ? LOADING : ERROR)
// If you are using Shopify's REST api, you need to provide `externalId`
// instead of `storefrontId`, and `productType`, something like this:
// const { product, loading } = useInventory({ ids: [externalId], productType: 'Product' })
const { products, status } = useInventory({ ids: [storefrontId] })
const { availableForSale } = products[storefrontId] || {}
useEffect(() => {
if (status === LOADING || !storefrontId) return
// if a product variant is available for sale,
// we set the button state to IDLE, we can deal with that later in the code
if (availableForSale) {
return setButtonState(IDLE)
}
// if any of the above conditions are not true, we can assume that
// the product is not available for sale, so we set the button state
// to SOLD_OUT
setButtonState(SOLD_OUT)
}, [loading, storefrontId])
// if the button state in place, feel free to use whatever approach you want
// to handle the different button states you might have
// for instance, something like this:
return (
<button
onClick={someAction}
disabled={buttonState === SOLD_OUT}
>
Add to Cart
</button>
)
}
With the useCartActions
you can use the helpers to get this information from the inventory (check the usecartactions-complete-example.js
tab below for a more thorough explanation) :
import { useCartState, useCartActions } from 'frontend-checkout'
const {
isProductAvailableForSale,
getProductQuantity,
} = useCartActions()
// variantId can be one of the following:
// From Product.variants for both REST & GraphQL - Shopify
// - REST = LineItem.variant_id
// - GraphQL = LineItem.variant.id
const isAvailableForSale = await isProductAvailableForSale({ id: variantId })
const quantity = await getProductQuantity({ id: variantId })
import React, { useState, useEffect } from 'react'
import { useCartActions } from 'frontend-checkout'
const IDLE = 'idle'
const LOADING = 'loading'
const SOLD_OUT = 'sold out'
const ERROR = 'error'
const AddToCartButton = ({
// let's assume storefrontId is coming via props
// from parent component, say ProductBox
storefrontId,
}) => {
// state to deal with button state
const [buttonState, setButtonState] = useState(storefrontId ? LOADING : ERROR)
const { isProductAvailableForSale } = useCartActions()
const checkAvailability = async () => {
const isAvailable = await isProductAvailableForSale(storefrontId)
// if a product variant is available for sale,
// we set the button state to IDLE, we can deal with that later in the code
if (isAvailable)
return setButtonState(IDLE)
}
// if any of the above conditions are not true, we can assume that
// the product is not available for sale, so we set the button state
// to SOLD_OUT
setButtonState(SOLD_OUT)
}
useEffect(() => {
if (!storefrontId) return
checkAvailability(storefrontId)
}, [storefrontId])
// if the button state in place, feel free to use whatever approach you want
// to handle the different button states you might have
// for instance, something like this:
return (
<button
onClick={someAction}
disabled={buttonState === SOLD_OUT}
>
Add to Cart
</button>
)
}
Comparing approaches
Approach using inventory directly
The cartState.inventory
updates using the productInventory.json
file generated by the backend, it contains all store products and productVariants and updates once in a minute.
To remove inventory delay, we are phasing out this approach after all the stores are migrated to one of the new approaches.
Why migrate?
- By using this approach, we're loading data for all products even if we are on the product page where we need data only for a single product.
- Data can be outdated, the delay between actual updates in inventory can be up to a minute.
- We can't change the interval for
productInventory.json
file loading in the Section code. - Not recommended for stores with a large inventory.
Approach using the useInventory hook.
The useInventory
hook makes an API request to get the same data but only for those products
/ productVariants
that we need:
- We load data only for those products that we need.
- Data updates immediately when it has been changed on the admin.
- We can set an optional interval that will make requests in the provided period to update data, or don't make it at all.
Updated 10 months ago