All Collections
Libraries
Frontend Checkout
Migrate to inventory actions and useInventory hook
Migrate to inventory actions and useInventory hook
Updated over a week ago

Overview

This is a guide on how to migrate from manually accessing the product inventory to using the new approaches available:

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

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.

deprecated-way.js

// 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):

using-useInventory-hook.js

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] || {}

useInventory-hook-complete-example.js

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) :

using-useCartActions.js

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 })

useCartActions-complete-example.js

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.

Did this answer your question?