CoursesSanity and Shopify with HydrogenFetching Sanity content

Sanity and Shopify with Hydrogen

Lesson
6

Fetching Sanity content

Log in to mark your progress for each Lesson and Task

Your front-end is only telling half the story. Bring your products to life with extra content from your Sanity project.

In many Remix projects, you'll never interact with the server.ts file. However in Hydrogen it comes preconfigured with the Storefront client with functions for fetching products and caching.

You'll extend this file with Sanity functions for data fetching.

The hydrogen-sanity package contains a number of useful functions to simplify querying and displaying content from Sanity.

Install hydrogen-sanity and other packages
npm install hydrogen-sanity @portabletext/react
  • @portabletext/react is a React component for rendering block content which is authored in Sanity Studio

Sanity Client allows you to query (and mutate) content.

You’ll need a Sanity Client configured with your Project ID and dataset name available to any route.

Add your Sanity project details to the Hydrogen project's .env file. You can find these either in sanity.io/manage or in the sanity.config.ts file of your Studio.

.env
# Project ID
SANITY_PROJECT_ID=""
# Dataset name
SANITY_DATASET=""
# (Optional) Sanity API version
SANITY_API_VERSION=""
Satisfy TypeScript by adding these variables to Remix's global types.
./env.d.ts
declare global {
// ...other Types
interface Env {
// ...other variables
SANITY_PROJECT_ID: string
SANITY_DATASET: string
SANITY_API_VERSION: string
SANITY_API_TOKEN: string
}
}

The code example below contains new lines to paste into your Hydrogen project’s server file.

Open ./server.ts and update it to include Sanity Client
./server.ts
// ...all other imports
// Add imports for Sanity Loader and Preview Session
import {createSanityLoader} from 'hydrogen-sanity'
import {
// ... all other @shopify/hydrogen imports
createWithCache,
} from '@shopify/hydrogen';
// Inside the default export
export default () => {
// ... Leave all other functions like the storefront client as-is
// (Prerequisite) If not already initialized, create a `withCache` handler...
const withCache = createWithCache({cache, waitUntil, request})
// 1. Configure the Sanity Loader and preview mode
const sanity = createSanityLoader({
// Required:
withCache,
// Required:
// Pass configuration options for Sanity client or an instantialized client
client: {
projectId: env.SANITY_PROJECT_ID,
dataset: env.SANITY_DATASET,
apiVersion: env.SANITY_API_VERSION || '2023-03-30',
useCdn: process.env.NODE_ENV === 'production',
},
})
// 2. Make Sanity available to all action and loader contexts
const handleRequest = createRequestHandler({
// ...other settings
getLoadContext: () => ({
// ...other providers
withCache,
sanity,
}),
})
}

Now a configured Sanity React Loader is available inside the Hydrogen “context” as sanity, just like the preconfigured storefront.

You'll use loadQuery to retrieve content from Sanity. It's configured in a way to make setting up Visual Editing simple. For now, you'll just use the initial data in the default export to render content.

Update the route for all product pages to query for Sanity content
./app/routes/products.$handle.tsx
import {json, type LoaderFunctionArgs} from '@shopify/remix-oxygen';
import {Link, useLoaderData} from '@remix-run/react';
import type {Product} from '@shopify/hydrogen/storefront-api-types';
import {PortableText} from '@portabletext/react';
import type {SanityDocument} from '@sanity/client';
import {groq} from 'hydrogen-sanity/groq';
export async function loader({
params,
context: {storefront, sanity},
}: LoaderFunctionArgs) {
const {product} = await storefront.query<{product: Product}>(
`#graphql
query Product($handle: String!) {
product(handle: $handle) { id title }
}
`,
{variables: params},
);
const query = groq`*[_type == "product" && store.slug.current == $handle][0]{
body,
"image": store.previewImageUrl
}`;
const initial = await sanity.loadQuery<SanityDocument>(query, params);
return json({product, initial});
}
export default function Page() {
const {product, initial} = useLoaderData<typeof loader>();
const page = initial.data;
return (
<div className="mx-auto p-12 prose prose-a:text-blue-500">
<h1 className="text-3xl font-bold">{product.title}</h1>
<img
alt={product.title}
src={page.image}
className="size-32 not-prose mb-6 mr-6 object-cover float-left rounded-xl"
/>
{page?.body?.length > 0 ? <PortableText value={page.body} /> : null}
<p>
<Link to="/products">&larr; Back to All Products</Link>
</p>
</div>
);
}
Read the documentation on GROQ for more on querying content from Sanity

Visit any product page now, and you should see both the product title from Shopify and the contents of the Portable Text field in the Sanity document for that same product.

If there's no extra text showing, edit the LULU Mini Pot product in your Studio and add the following text:

All of our products are made from 100% recycled materials and are finished with a waterproof sealant. We recommend cleaning your LULU Pot regularly with hot soapy water. Please do not leave the pot to soak. Alternatively our products are dishwasher safe.

Your page should now look like this.

If your CSS looks slightly off, try emptying the contents of reset.css as it conflicts with some Tailwind Typography styles.

Your Hydrogen app now queries content from both Sanity and Shopify independently, displaying in a consistent front-end.

Sanity content is more than just a paragraph of text – let’s embellish this with some rich content blocks!