XM Cloud - Getting component specific data

If you are binding your component with the layout response but feel that if a custom property can come in the layout response and you could bind that in your component.

But as you know you can not insert the custom property in the layout response without heavy customisation but we have a way to do so.

We can achieve this on component level using  useComponentProps and  getStaticProps: GetStaticComponentProps methods in XM cloud.

Lets understand this quickly.

You have a component like follows:

import type {
  ComponentRendering,
  Field,
  GetStaticComponentProps,
  ImageField,
  LayoutServiceData,
  LinkField,
} from '@sitecore-jss/sitecore-jss-nextjs';
import { useComponentProps } from '@sitecore-jss/sitecore-jss-nextjs';
type BlogIndexVariationOneProps = ComponentProps & {
  fields?: BlogIndexVariationOneFields;
};

function BlogIndexVariationOne({
  fields = {},
  rendering = {} as ComponentRendering,
}: BlogIndexVariationOneProps) {

const path = useComponentProps<string>(rendering?.uid);

return (
// your html here
)

}

In the component BlogIndexVariationOne we are passing the BlogIndexVariationOneProps. In this fields will be mapped from the layout response but rendering is worth to pay attention here that we will discuss the usage of it further in this blog.

Now assume that under this component you are returning the HTML with the data received in the fields object and additionaly you have a requirement to show the current page URL in any of the <div> tag also.

So as you know the current url will not work from  window.location.href or writing the same in the useEffect() or even useLocation() won't work until you don't wrap your component in the <Router> tag.

So how can we get the current url then? Here we will use the getStaticProps: GetStaticComponentProps method as shown below:

export const getStaticProps: GetStaticComponentProps = async (

  _rendering: ComponentRendering,
  layoutData: LayoutServiceData,
  context
) => {
  return context?.params?.requestPath
}

Here we are returning the requestPath provided by sitecore's context and it is returning the string type. 

Now how will we use this in our component? Here comes the role of rendering that we passed in the component in the line const path = useComponentProps<string>(rendering?.uid);. So rendering?.uid in the useComponentProps tells the component that something is being passed from getStaticProps: GetStaticComponentProps as string return type so use that.

And voilla, now you can use the request path in your code.

So in place of context?.params?.requestPath you can use your any API fetch if you want it to be fetched using this although the best practice for getting the API data is to use in the useEffect() but this is also one more way to use.

Thanks!

To extend it further with one more example.

In Sitecore JSS / XM Cloud projects (especially with Next.js),
each component can export a getStaticProps method that defines how to fetch its data during build time or static regeneration.

The framework (Sitecore + Next.js) runs this function:

  • once at build time for static generation (next build), or

  • on demand when the page is rebuilt (ISR).

The result of this function gets attached to the component rendering JSON as componentProps — which is what useComponentProps(uid) later reads.


Suppose you have method as follows that get the data using graphql query:

export const getStaticProps: GetStaticComponentProps = async ( _rendering: ComponentRendering, layoutData: LayoutServiceData, context ) => { // Create a GraphQL client to talk to Sitecore XM Cloud const graphQLClient = new GraphQLRequestClient(config.graphQLEndpoint, { apiKey: config.sitecoreApiKey, }); // Get the current page path (used to construct URLs) const basePath = (layoutData?.sitecore?.context?.itemPath ?? '').replace(/\/,-w-,/, ''); /* page query param handling */ const page = (() => { const path = context?.params?.requestPath; if (path === undefined) return ''; if (!Array.isArray(path)) return ''; const pageNumber = parseInt(path[path.length - 1]); if (isNaN(pageNumber)) return ''; return pageNumber.toString(); })(); /* fetch blog articles */ let updatedResult = []; let query = CHILD_BLOGS_GQL; // Replace placeholders in the GraphQL query with actual IDs query = query.replaceAll('__ROOT_ID__', Constants?.Ids?.BlogItemParent); query = query.replaceAll('__TEMPLATE_ID__', Constants?.TemplateIds?.BlogDetailPage); // Execute the GraphQL query and return all articles updatedResult = await getAllItems<BlogTemplat>(graphQLClient, query); // Return the data that will be serialized into componentProps return { page: page, result: updatedResult, basePath: basePath }; };

and the top somewhere when you would have started your component, there will be code like

const query = useComponentProps<queryResult>(rendering?.uid);
  const data = query?.result;

and,

then do you logic operation based on data variable.

1 comment:

  1. https://sitecorepeanuts.blogspot.com/2024/07/xm-cloud-getting-component-specific-data.html

    ReplyDelete

Troubleshoot personalization on xm cloud

Here are the troubleshooting steps below that helped personalization to work. We checked the events analytics in the page builder but it was...