Fetch data in a component
Developer preview
Goal: show data from a different API in a Uniform component. For example, an author enters a product ID, and the component gets the name and the price of the product from your commerce API.
Prerequisites#
- A Next.js app with the SDK. Refer to Next.js App Router SDK.
- A component definition
productCardwith a text parameterproductId.
Step 1: Make the data function#
Make a function that gets the product. Give the fetch a cache tag, so that you can revalidate the product later:
lib/products.ts
cache: "force-cache" keeps the response in the Next.js data cache. Without this option, Next.js 16 does not keep the response in the data cache. revalidate: 3600 sets a maximum age of one hour.
With Cache Components#
If you set cacheComponents: true in next.config.ts, use the "use cache" directive in place of the fetch options:
lib/products.ts
Use this version only with Cache Components. The "use cache" directive works only when cacheComponents is true.
Step 2: Make an async server component#
A Uniform component is a React Server Component. Thus it can be async, and it can wait for the data:
components/product-card.tsx
Step 3: Register the component with a Suspense fallback#
Without a Suspense boundary, the page waits for the slowest component. Add the suspense option in resolveComponent. The SDK then puts the component in a React Suspense boundary. The page shows the fallback first, and the product streams in when its data is ready:
components/resolveComponent.tsx
fallback is a component, not an element. The SDK renders it with no props.
note
In Canvas, each change of the author refreshes the page. A component with a Suspense boundary then shows its fallback again. Use suspense only for components that are slow. Refer to Streaming with Suspense.
Step 4 (optional): Use dynamic inputs from the project map#
A project map node can have a dynamic segment, for example /products/:productId. All product pages then use one composition. The component reads the value of the segment in context.dynamicInputs, not in a parameter:
components/product-detail.tsx
For the URL /products/shoe-42, context.dynamicInputs.productId is "shoe-42". The example in step 3 registers ProductDetail without suspense. A component in a Suspense boundary can stream after Next.js sends the status code. Thus do not use suspense for a component that calls notFound().
Use a parameter when the author selects the data. Use a dynamic input when the URL selects the data.
| Data source | Read it in | Example |
|---|---|---|
| A parameter | parameters.productId?.value | A product card on a landing page |
| A dynamic input | context.dynamicInputs.productId | A product detail page for each product |
dynamicInputs comes from the Route API. A composition from resolveCompositionById or resolveCompositionBySlug has no dynamic inputs, so context.dynamicInputs is an empty object.
Notes#
- Revalidation: to get new product data before the cache expires, call
revalidateTag("product:shoe-42", "max")in a route handler or a Server Action. For example, call it from a webhook of your commerce system. Refer to the Next.jsrevalidateTagreference. - Preview: Canvas preview uses Next.js draft mode. In draft mode, Next.js does not use the fetch cache. Thus authors always see the current product data.
- The same fetch in more than one component: Next.js does the same
GETrequest one time for each render, also without a cache. Thus two components can callgetProductwith the same ID. - Change the composition data: to change parameters or slots before the components render, for example with Uniform enhancers, resolve the composition on the page. Refer to Change the composition data before render.