Problem
An e-commerce business wants to display dynamic product details on its website using data from an external Product Information Management (PIM) system. The product details, such as descriptions, prices, availability, and images, are stored in the external system and need to be fetched dynamically based on the product being viewed.
The following content is valid for both third-party integrations and retrieving data from XM Cloud.
Solution
There are 3 main options to get component specific data:
- Integrated GraphQL
- Component level data fetching
- Connected GraphQL
Integrated GraphQL can be utilized based on the use cases that you have but there are limitations in the extensibility and publishing performance.
Integrated GraphQL
Integrated GraphQL directly affects the layout data shape returned for a specific component by the Experience Edge layout response.
A GraphQL query can be defined on the rendering item that shapes the data returned and can be used from the props.fields
object in the same way as a standard response. This gives the developer more control over the shape of the data being returned.
To add IGQL to your component, you can add the query to the Component GraphQL Query
field on the rendering item.
When using integrated GraphQL queries, for the default and jss layout service configurations, values for $datasource
, $contextItem
, and $language
are automatically injected.
Integrated GraphQL is executed when the content is published to Experience Edge. On building the layout data, if a component contains IGQL, a REST API call is made to the Edge preview end point on the CM. These API calls are not asynchronous. If you make a complex query for your component that requires multiple REST API calls, this will impact the publishing performance.
Connected GraphQL
Connected GraphQL is similar to Component Level Data Fetching in that a GraphQL call is made to the Experience Edge API to get the content, but instead of running this a build time, it is done on the client. This method is identical to using a GraphQL API in any JavaScript application and is not JSS-specific.
Component Level Data Fetching
To get component level data, you can use a similar approach to page level data fetching. The JSS ComponentPropsService looks for getStaticProps
or getServerSideProps
functions when rendering a component.
If a component defines and exports these functions, the ComponentPropsService
class runs the function. After applying all side effects, it stores the component data in a componentProps
object in the format { [rendering.uid]: data }
.
IMPORTANT
Because the getStaticProps
and getServerSideProps
are functions provided by JSS, these functions will be included in the client bundle. Do not include any secrets or sensitive information in any of these component-level functions.
Also included in the client bundle are any imports that the function depends on, even if the client-side code does not use the imports.
This does not affect page-level getStaticProps
and getServerSideProps
functions.
import { Text, RichText, Field, GetServerSideComponentProps, GetStaticComponentProps, withDatasourceCheck } from '@sitecore-jss/sitecore-jss-nextjs';
import { ComponentParams, ComponentRendering } from '@sitecore-jss/sitecore-jss-nextjs';
type ComponentProps = {
rendering: ComponentRendering;
params: ComponentParams;
};
type ContentBlockProps = ComponentProps & {
fields: {
heading: Field<string>;
content: Field<string>;
};
};
const ContentBlock = ({ fields }: ContentBlockProps): JSX.Element => (
<div className="contentBlock">
<Text tag="h2" className="contentTitle" field={fields.heading} />
<RichText className="contentDescription" field={fields.content} />
</div>
);
const fetchPost = () => fetch('https://jsonplaceholder.typicode.com/posts/1').then((res) => res.json());
export const getStaticProps: GetStaticComponentProps = async (rendering, layoutData, context) => {
const post = await fetchPost();
return post;
};
export const getServerSideProps: GetServerSideComponentProps = async (rendering, layoutData) => {
const post = await fetchPost();
return post;
};
export default withDatasourceCheck()<ContentBlockProps>(ContentBlock);
In the example above, the component contains both implementations of
getStaticProps
andgetServerSideProps
. In a real component, you must only define one of them and it should match the type of page level data fetching for the route this component would be used on.
Discussion
Integrated GraphQL vs Connected GraphQL vs Component Level Data Fetching
When should you use each one?
We recommend you use integrated GraphQL when:
- Your component requires more data than the datasource template fields that are part of the GraphQL schema.
- The datasource template contains extra fields that you do not want to render.
If the component only uses content template field data, there is no need to write extra GraphQl, the default layout data is sufficient to render the fields.
We recommend you use connected GraphQL when:
-
You want to load data asynchronously after the page layout is rendered, or in response to app state changes other than route change.
-
The component has to run mutations (updates) or subscriptions (real-time data).
-
You want full control over the lifecycle of your queries and states, such as integration with Redux or the apollo-link-state package.
We recommend you use Component Level Data Fetching when:
-
You need to get data from an external data source, but you want the content generated on build or server-side vs client-side.
-
You want to improve SEO by having the content available on page load vs a client-side async load.
-
You have a complex query to execute.
-
You want to improve publishing times and are ok with a slight increase in generation time.
-
You are using wildcard pages and you need to get the dynamic data at generation time.