-
Notifications
You must be signed in to change notification settings - Fork 281
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add an optimistic product hook (#2183)
* Add a `useOptimisticProduct` hook
- Loading branch information
Showing
10 changed files
with
457 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
--- | ||
'@shopify/hydrogen': patch | ||
--- | ||
|
||
Add a `useOptimisticProduct` hook for optimistically rendering product variant changes. This makes switching product variants instantaneous. Example usage: | ||
|
||
```tsx | ||
function Product() { | ||
const {product: originalProduct, variants} = useLoaderData<typeof loader>(); | ||
|
||
// The product.selectedVariant optimistically changed during a page | ||
// transition with one of the preloaded product variants | ||
const product = useOptimisticProduct(originalProduct, variants); | ||
|
||
return <ProductMain product={product} />; | ||
} | ||
``` | ||
|
||
This also introduces a small breaking change to the `VariantSelector` component, which now immediately updates which variant is active. If you'd like to retain the current functionality, and have the `VariantSelector` wait for the page navigation to complete before updating, use the `waitForNavigation` prop: | ||
|
||
```tsx | ||
<VariantSelector | ||
handle={product.handle} | ||
options={product.options} | ||
waitForNavigation | ||
> | ||
... | ||
</VariantSelector> | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import {ReferenceEntityTemplateSchema} from '@shopify/generate-docs'; | ||
|
||
const data: ReferenceEntityTemplateSchema = { | ||
name: 'useOptimisticProduct', | ||
category: 'hooks', | ||
isVisualComponent: false, | ||
related: [ | ||
{ | ||
name: 'VariantSelector', | ||
type: 'components', | ||
url: '/docs/api/hydrogen/2024-04/components/variantselector', | ||
}, | ||
{ | ||
name: 'useOptimisticCart', | ||
type: 'hooks', | ||
url: '/docs/api/hydrogen/2024-04/hooks/useoptimisticcart', | ||
}, | ||
], | ||
description: `The \`useOptimisticProduct\` takes an existing product object, processes a pending navigation to a product variant, and locally mutates the product with optimistic state. This makes switching product options immediate. It requires that the product query include a \`selectedVariant\` field populated by \`variantBySelectedOptions\`.`, | ||
type: 'component', | ||
defaultExample: { | ||
description: 'I am the default example', | ||
codeblock: { | ||
tabs: [ | ||
{ | ||
title: 'JavaScript', | ||
code: './useOptimisticProduct.example.jsx', | ||
language: 'jsx', | ||
}, | ||
{ | ||
title: 'TypeScript', | ||
code: './useOptimisticProduct.example.tsx', | ||
language: 'tsx', | ||
}, | ||
], | ||
title: 'Example code', | ||
}, | ||
}, | ||
definitions: [ | ||
{ | ||
title: 'Props', | ||
type: 'UseOptimisticProductGeneratedType', | ||
description: '', | ||
}, | ||
], | ||
}; | ||
|
||
export default data; |
22 changes: 22 additions & 0 deletions
22
packages/hydrogen/src/product/useOptimisticProduct.example.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import {useLoaderData} from '@remix-run/react'; | ||
import {defer} from '@remix-run/server-runtime'; | ||
import {useOptimisticProduct} from '@shopify/hydrogen'; | ||
|
||
export async function loader({context}) { | ||
return defer({ | ||
product: await context.storefront.query('/** product query **/'), | ||
// Note that variants does not need to be awaited to be used by `useOptimisticProduct` | ||
variants: context.storefront.query('/** variants query **/'), | ||
}); | ||
} | ||
|
||
function Product() { | ||
const {product: originalProduct, variants} = useLoaderData(); | ||
|
||
// The product.selectedVariant optimistically changed during a page | ||
// transition with one of the preloaded product variants | ||
const product = useOptimisticProduct(originalProduct, variants); | ||
|
||
// @ts-ignore | ||
return <ProductMain product={product} />; | ||
} |
22 changes: 22 additions & 0 deletions
22
packages/hydrogen/src/product/useOptimisticProduct.example.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import {useLoaderData} from '@remix-run/react'; | ||
import {defer, LoaderFunctionArgs} from '@remix-run/server-runtime'; | ||
import {useOptimisticProduct} from '@shopify/hydrogen'; | ||
|
||
export async function loader({context}: LoaderFunctionArgs) { | ||
return defer({ | ||
product: await context.storefront.query('/** product query */'), | ||
// Note that variants does not need to be awaited to be used by `useOptimisticProduct` | ||
variants: context.storefront.query('/** variants query */'), | ||
}); | ||
} | ||
|
||
function Product() { | ||
const {product: originalProduct, variants} = useLoaderData<typeof loader>(); | ||
|
||
// The product.selectedVariant optimistically changed during a page | ||
// transition with one of the preloaded product variants | ||
const product = useOptimisticProduct(originalProduct, variants); | ||
|
||
// @ts-ignore | ||
return <ProductMain product={product} />; | ||
} |
Oops, something went wrong.