# useOptimisticVariant The `useOptimisticVariant` takes an existing product variant, processes a pending navigation to another product variant, and returns the data of the destination variant. This makes switching product options immediate. ### Example code ```jsx import {useLoaderData} from '@remix-run/react'; import {defer} from '@remix-run/server-runtime'; import {useOptimisticVariant} 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 `useOptimisticVariant` variants: context.storefront.query('/** variants query **/'), }); } function Product() { const {product, variants} = useLoaderData(); // The selectedVariant optimistically changes during page // transitions with one of the preloaded product variants const selectedVariant = useOptimisticVariant( product.selectedVariant, variants, ); // @ts-ignore return <ProductMain selectedVariant={selectedVariant} />; } ``` ```tsx import {useLoaderData} from '@remix-run/react'; import {defer, LoaderFunctionArgs} from '@remix-run/server-runtime'; import {useOptimisticVariant} 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 `useOptimisticVariant` variants: context.storefront.query('/** variants query */'), }); } function Product() { const {product, variants} = useLoaderData<typeof loader>(); // The selectedVariant optimistically changes during page // transitions with one of the preloaded product variants const selectedVariant = useOptimisticVariant( product.selectedVariant, variants, ); // @ts-ignore return <ProductMain selectedVariant={selectedVariant} />; } ``` ## Props ### UseOptimisticVariantGeneratedType #### Returns: OptimisticVariant<SelectedVariant = OptimisticVariantInput> A new product object where the `selectedVariant` property is set to the variant that matches the current URL search params. If no variant is found, the original product object is returned. The `isOptimistic` property is set to `true` if the `selectedVariant` has been optimistically changed. #### Params: - selectedVariant: SelectedVariant - variants: Variants export function useOptimisticVariant< SelectedVariant = OptimisticVariantInput, Variants = OptimisticProductVariants, >( selectedVariant: SelectedVariant, variants: Variants, ): OptimisticVariant<SelectedVariant> { const navigation = useNavigation(); const [resolvedVariants, setResolvedVariants] = useState< Array<PartialDeep<ProductVariant>> >([]); useEffect(() => { Promise.resolve(variants) .then((productWithVariants) => { if (productWithVariants) { setResolvedVariants( productWithVariants instanceof Array ? productWithVariants : (productWithVariants as PartialDeep<ProductVariant>).product ?.variants?.nodes || [], ); } }) .catch((error) => { reportError( new Error( '[h2:error:useOptimisticVariant] An error occurred while resolving the variants for the optimistic product hook.', { cause: error, }, ), ); }); }, [JSON.stringify(variants)]); if (navigation.state === 'loading') { const queryParams = new URLSearchParams(navigation.location.search); let reportedError = false; // Find matching variant const matchingVariant = resolvedVariants.find((variant) => { if (!variant.selectedOptions) { if (!reportedError) { reportedError = true; reportError( new Error( '[h2:error:useOptimisticVariant] The optimistic product hook requires your product query to include variants with the selectedOptions field.', ), ); } return false; } return variant.selectedOptions.every((option) => { return queryParams.get(option.name) === option.value; }); }); if (matchingVariant) { return { ...matchingVariant, isOptimistic: true, } as OptimisticVariant<SelectedVariant>; } } return selectedVariant as OptimisticVariant<SelectedVariant>; } ### OptimisticVariant T & { isOptimistic?: boolean; } ### OptimisticVariantInput PartialDeep<ProductVariant> ## Related - [VariantSelector](/docs/api/hydrogen/2024-10/components/variantselector) - [useOptimisticCart](/docs/api/hydrogen/2024-10/hooks/useoptimisticcart)