Component Level Data Fetching using GraphQL in Next Js Applications
Overview
There may be a scenario where we have to fetch the component data within the component itself like a Product Grid etc., Because we may want to have this components to behave independently and to have it less coupled from the page level data. With this in mind, the Component Level Data fetching would be more useful and still we can achieve the benefit of pre-rendering etc.,
In the Helix example site, the approach may look like this,

There are different data fetching methods available in Next.js to build the pages in build time or to build the page on each requests.
As such, there are also options available in Next.js if we want to fetch the component level data within the component itself. We need to follow the similar methods like getStaticProps for the Static Generation or getServerSideProps for the Server-Side rendering.
How Next Js identifies which component requires the data fetching ?
If we take a look at the SitecorePagePropsFactory class, it uses an instance of the ComponentPageService class that fetches the component data depending upon the mechanism we use SSR/SSG.

If the pre-rendering method is SSG, then it uses fetchStaticComponentProps and if the pre-rendering method is SSR, then it uses fetchServerSideComponentProps.

How we are going to achieve the Component level data fetching within the component ?
If a component defines and exports a getServerSideProps or getStaticProps function, then the ComponentPropsService runs the function.

Then within the component we have to use the useComponentProps
We will be seeing this with an example.
I have used the helix repo to play around this concept. Feel free to fork this and follow the instructions to set it up in the local.
With the introduction of the component level data fetching, the above diagram will change like below,

Header Component as an example
From this repo, I have taken the Header component for now to understand this component level data fetching and to apply it there.
This header component already uses React’s DataContext ( as this is a navigation and should be available throughout the site). The value to the Navigation Data context is fetched in the SitecorePagePropsFactory like below.

And this navigation data is fed to the NavigationDataContext in the [[..path]].tsx file like below.

This is how it works currently. I will be changing this behaviour using the component level data fetching mechanism we see earlier.
Applying Component Level Data Fetching with GraphQL to the Header Component
If you take a look at the header component, it uses the below graphql query which we also will be using for the component level data fetching.

When you access the site and if you take a closer look at the docker running logs of the rendering container, you will be seeing something like this,

What does this mean ? – This repo is using the library graphql-let – It is actually a code generator that converts all the .graphql files within the solution into the .d.ts file that has strongly exported types. So we can import those graphql queries into our component as needed.

The required configuration for the graphql-let library is already done in the Helix example repo, so we do not have to worry much about it. But you can take a look here to know more about it.
As first step, we need to import the below types in our component file.

Then we also have to import the required graphql queries. As mentioned, we have used graphql-let, so the import is possible like below.

As a next step, we have to define any one of the getStaticProps or getServerSideProps functions. Here we are going to use getStaticProps and it looks like below,

Above, we are forming the GraphQLRequestClient object with end point configuration from the config file and we are making an request with the type ‘NavigationQuery‘. And we are passing ‘NavigationDocument‘ of type Documentnode.
‘NavigationQuery‘ and ‘NavigationDocument‘????? – Yes. It comes from the graphql-let generated file. Now we got how useful this awesome library is.
Now we have defined the getStaticProps function and exported it. Let us see how to use it from the component to access the data.
Accessing the Component Data
We have to use the useComponentProps

Once we have access to the data, we can use it to build our component as needed.
The modified Header component looks like below,
| import React from 'react'; | |
| import { | |
| _NavigationItem, | |
| Item, | |
| HomePage, | |
| NavigationDocument, | |
| NavigationQuery, | |
| } from './Navigation.graphql'; | |
| import NextLink from 'next/link'; | |
| import { | |
| GetStaticComponentProps, | |
| useComponentProps, | |
| GraphQLRequestClient, | |
| ComponentRendering, | |
| } from '@sitecore-jss/sitecore-jss-nextjs'; | |
| import config from '../../temp/config'; | |
| import { SitecoreTemplates } from '../../lib/sitecoreTemplates'; | |
| type NavItem = _NavigationItem & Item; | |
| export type ProductListProps = { | |
| rendering: ComponentRendering; | |
| }; | |
| const Header = ({ rendering }: ProductListProps): JSX.Element => { | |
| // Access the data with the useComponentProps |
|
| const data = useComponentProps |
|
| const items = [data?.item, ...(data?.item?.children.results as NavItem[])]; | |
| const homeItem = data?.item as HomePage; | |
| return ( | |
| {homeItem && ( | |
| | |
| src={homeItem.headerLogo?.src || ''} | |
| alt={homeItem.navigationTitle?.value || 'Home'} | |
| /> | |
| )} | |
| role="button" | |
| className="navbar-burger burger" | |
| aria-label="menu" | |
| aria-expanded="false" | |
| data-target="navbarBasicExample" | |
| > | |
| {items && | |
| items?.map((item, index) => { | |
| const navItem = item as NavItem; | |
| return ( | |
| |
|
| {navItem?.navigationTitle?.value} | |
| ); | |
| })} | |
| ); | |
| }; | |
| export const getStaticProps: GetStaticComponentProps = async (rendering, layoutData) => { | |
| if (process.env.JSS_MODE === 'disconnected') { | |
| return null; | |
| } | |
| // To make the GraphQLClient Request | |
| const graphQLClient = new GraphQLRequestClient(config.graphQLEndpoint, { | |
| apiKey: config.sitecoreApiKey, | |
| }); | |
| const result = await graphQLClient.request |
|
| rootPath: layoutData.sitecore.route?.itemId, // root path | |
| language: layoutData.sitecore.context.language, // context language | |
| templateId: SitecoreTemplates.PageTypes.Id, // page template Ids | |
| }); | |
| console.log('GraphQL Result is ' + JSON.stringify(result)); | |
| return result; | |
| }; | |
| export default Header; |
Let us run the site to see the changes
Once you do these changes, run the site with ‘jss start:connected’ and observe the logs we have written,

We can notice that the GraphQLComponentService automatically calls our getStaticProps functions and the responses are fetched. We can access them with the useComponentProps

Note:-
Current way of implementation of the navigation component would be the correct one with React contexts. I have modified this particularly to play around the topic Component level data fetching.
Next I will be exploring on using this Component Level Data fetching with useSWR – Another cool library to fetch the data with GraphQL queries.
Stay tuned….!!!!
References
