Component-level data fetching in Sitecore JSS with Next.js

Rainbow colored computer chip internals

Component-level data fetching is a unique feature of Sitecore JSS with Next.js. It lets you build better-architected frontend applications by allowing for more independent modular components.

What are you going to learn from this article:

  • How vanilla Next.js limits you in data fetching
  • Implementing component-level data fetching in your Next.js Sitecore JSS app
  • How the advanced Incremental Static Regeneration (ISR) feature works at the component level.

💡 What do I mean by data fetching?

When I say ‘data fetching’ I mean gathering up the content to build out the page and experience that you want for your visitors. So data fetching could be making an API request to your content management system (CMS), loading images from your cloud provider, calling your personalization engine, or so many other things.

Data Fetching in Next.js WITHOUT Sitecore JSS

Taking a step back let’s first take a look at data fetching in vanilla Next.js application, meaning no Sitecore JSS. Page level data fetching is expected for vanilla Next.js applications. This approach of fetching data at a page level works, but your data fetching methods can get overwhelming quickly if you have to collect lots of data for all the components on your page.

What bugs me the most about page-level data fetching is the inability to build completely independent components. You have to rely on the parent page level for data fetching and then passing that data down to the child components. This gets even worse when you have children of children components like the animation below.

Data fetching in Next.js without Sitecore JSS

Data Fetching in Next.js with Sitecore JSS

The Sitecore JSS team has expanded the data fetching capabilities of Next.js by allowing for component-level data fetching. This means no more passing data from the parent into child components. We can fetch that data within the components ourselves, this keeps our frontends modular and follows the separation of concerns principles. See my previous blog post Modular Frontends with Component Driven Design to learn more about why this is important.

You can call the getStaticProps or getServerSide props methods within components to fetch the data you need. This means it works for both static and server-side rendered components!

For you to implement component-level data fetching it’s a little different than page level. So let’s look at those differences now and utilize component-level data fetching.

Component-level data fetching with Sitecore JSS and Next.js

Implementing Component-Level Data Fetching

Here you can find the official Sitecore documentation on component-level data fetching. For the most part data fetching in the component is pretty similar to your pages. You create your asynchronous data fetching function, getStaticProps or getServerSideProps, and inside of that you call out to your file system, API, database, or wherever your data lives. The differences start with what you return from your data fetching method and how you access that data within your component.

GetStaticComponentProps & GetServerSideComponentProps Return types

GetStaticComponentProps and GetServerSideComponentProps are the two return types for the static and server-side data fetching methods. These differ from the standard page-level data fetching return types. The biggest difference with these return types is that instead of returning a properties object you return your data object directly. Need JSON data in your component, use your data fetching method to get it and return it directly.

Static data example (💡 Don’t forget GetStaticComponentProps return type)

1 2import { GetStaticComponentProps } from '@sitecore-jss/sitecore-jss-nextjs'; 3 4export const getStaticProps: GetStaticComponentProps = async (rendering, layoutData, context) => { 5 const post = await fetch('MyApiEndpoint').then((res) => res.json()); 6 return post; 7};

Server-side data example (💡 Don’t forget GetServerSideComponentProps return type)

1import { GetServerSideComponentProps} from '@sitecore-jss/sitecore-jss-nextjs'; 2 3export const getServerSideProps: GetServerSideComponentProps = async (rendering, layoutData) => { 4 const post = await fetch('MyApiEndpoint').then((res) => res.json()); 5 return post; 6};

Rendering UID for accessing your data

The next important piece to cover is how to access your component-level data. This is where the rendering UID comes in. Each component has a unique rendering UID that you will need to pass into the special useComponentProps function inside of your function that exports HTML for the page.

1import { useComponentProps, ComponentRendering, Field } from '@sitecore-jss/sitecore-jss-nextjs'; 2 3type ComponentData = { 4 rendering: ComponentRendering; 5 fields: { 6 Title: Field<string>; 7 SessionizeURL: Field<string>; 8 }; 9}; 10 11export const Default = (props: ComponentData): JSX.Element => { 12 const externalData = useComponentProps<string>(props.rendering.uid); 13 14 return ( 15 <div> 16 { externalData } 17 </div> 18 ); 19};

There is a decent bit of code shown above so let’s explain it a bit. First, we’ll look at the ComponentData object. The rendering property, with the type ComponentRendering, is the most important. That holds the UID you need.

The fields property is the data coming from Sitecore XM Cloud, the hybrid headless CMS, so it’s optional based on your use case. At a minimum, you need the ComponentRendering property so you have the UID to access the data.

The next important piece is the call to useComponentProps. This is a special Sitecore JSS method that fetches the data we returned from our getStaticProps or getServerSideProps methods. The <string> in the method call indicates we expect a string to be returned. And the props.rendering.uid is the unique component UID, which JSS uses to determine what data to return to this component.

💡 It’s important to note that useComponentProps can return undefined if no data is found based on the UID. So keep that in mind when accessing the externalData variable later on in your function.

Last, inside the HTML we have access to our data and we can use it however we want. In the above case, it is a string so it’s directly being printed in the HTML.

Component-level data fetching and incremental static regeneration

A useful feature of Next.js data fetching is incremental static regeneration (ISR). This feature allows for static pages to be regenerated with new content without having to do a full rebuild. But ISR works at a page level, how do you use ISR when fetching data in the component?

❔ Not familiar with Incremental Static Regeneration? Find more information in my blog: Build Times & Incremental Static Regeneration to the Rescue.

The way ISR works with component-level data fetching is that it will inherit ISR from the parent page. You do not implement ISR in the component. If the parent page that hosts your component has ISR implemented, meaning it has its revalidate property set to some value in getStaticProps, then your component will automatically inherit that and update in the same time interval.

Components inherit Incremental Static Regeneration (ISR) properties from the parent page

This does mean ISR will regenerate components with new data, which is great, but it is not very flexible. Let's say you didn’t want or need ISR for your child component, unfortunately, there is no way to turn ISR off in your component. This isn’t the end of the world but could mean unecessary API calls are made.

Summary

The ability to perform component-level data fetching in Next.js with Sitecore JSS allows you to put your data fetching calls exactly where you need them instead of at a page level and passing your data around. This helps to keep your components more independent and modular.

Component-level data fetching even works with ISR so you reduce build times and keep your page content up to date.

This is a great feature of Sitecore JSS and helps it stand out as a headless development tool. Special thanks to Adam Brauer and the whole Sitecore JSS team for help with implementing this feature on my own app and for sharing details on how ISR works inside your components.

Find the official Sitecore documentation on component-level data fetching here: Component-Level Data Fetching Documentation

Find more information about Sitecore JSS and the Headless Services here: Sitecore Developer Portal Headless Services