Skip to content

React Integration

Terminal window
npm install @kachingappz/bundles-react
# or
yarn add @kachingappz/bundles-react
# or
pnpm add @kachingappz/bundles-react

1. Set up the deferred data loader:

import {
KachingBundle,
fetchKachingBundlesData,
} from "@kachingappz/bundles-react"
function loadDeferredData({ context, params }, productId, dealBlockId) {
const kachingBundlesData = fetchKachingBundlesData(context.storefront, {
productId,
dealBlockId, // optional — specify which deal block to display
})
return {
kachingBundlesData,
}
}

2. Render the component in your product page:

const { kachingBundlesData } = useLoaderData()
return (
<ClientOnly>
<Await resolve={kachingBundlesData}>
{(data) => (
<KachingBundle
data={data}
selectedVariantId={selectedVariant.id}
onLinesChange={(lines) => setLines(lines)}
/>
)}
</Await>
</ClientOnly>
)

Use a useEffect to fetch data client-side and avoid server-side rendering issues with the web component:

import {
KachingBundle,
fetchKachingBundlesData,
} from "@kachingappz/bundles-react"
const [kachingBundlesData, setKachingBundlesData] = useState(null)
useEffect(() => {
const loadData = async () => {
const data = await fetchKachingBundlesData(
{
shopifyDomain: "your-store.myshopify.com",
storefrontAccessToken: "your-storefront-access-token",
},
{
productId: "gid://shopify/Product/123456789",
dealBlockId: "abc123", // optional
country: "US", // optional
language: "EN", // optional
},
)
setKachingBundlesData(data)
}
loadData()
}, [])
{
kachingBundlesData && (
<KachingBundle
data={kachingBundlesData}
selectedVariantId={selectedVariant.id}
onLinesChange={(lines) => {
// lines structure:
// [
// {
// merchandiseId: "gid://shopify/ProductVariant/123456789",
// quantity: 2,
// attributes: [{ key: "__kaching_bundles", value: "{ id: 'abc' }" }],
// sellingPlanId: "gid://shopify/SellingPlan/987654321" // optional
// }
// ]
setLines(lines)
}}
/>
)
}

If bundle data is not yet available (e.g., during development or design), render the widget in preview mode:

<KachingBundle
preview={{
price: 19.99,
color: "#00CC6A",
cornerRadius: 10,
}}
/>

If your storefront renders inside an iframe (e.g., a page builder preview), pass the iframe’s window object via the targetWindow prop. This ensures the widget’s CSS and JavaScript are injected into the correct document.

import Frame, { FrameContextConsumer } from "react-frame-component"
import { KachingBundle } from "@kachingappz/bundles-react"
<Frame>
<FrameContextConsumer>
{({ window: iframeWindow }) => (
<KachingBundle
targetWindow={iframeWindow}
data={kachingBundlesData}
/>
)}
</FrameContextConsumer>
</Frame>

fetchKachingBundlesData accepts any of the following clients as its first argument:

  • @shopify/hydrogen — pass context.storefront directly
  • @shopify/react-hydrogen
  • @shopify/storefront-api-client — pass a plain client config object { shopifyDomain, storefrontAccessToken }