Powerful Custom Hooks for Optimizing Next.js in Sitecore XM Cloud Environments: Part 1

Learn to enhance Sitecore XM Cloud with custom hooks, improving localization and personalization for a more engaging user experience.

January 26, 2024

By Sohrab Saboori

In the dynamic world of web development, the integration of Next.js with Sitecore XM Cloud is like opening a new chapter. It's not just about technology; it's about how we can make web development smarter and more intuitive.

In this blog, we're diving into the world of custom hooks in React, which are much more than just a technical feature—they're a game-changer in how we handle data and breathe life into our applications. These hooks aren't just about coding; they're about creating harmony between Next.js's smart server-side magic and Sitecore's robust content management, making our digital creations more efficient and user-friendly. Join us as we explore how custom hooks can transform your web applications, making them not just functional but remarkably efficient and effective in a Next.js and Sitecore XM Cloud ecosystem.

Custom Hook: useFetchItemFields

In our quest to enhance our Next.js applications with Sitecore XM Cloud, let's start with our first powerful custom hook: useFetchItemFields. This hook simplifies fetching data from Sitecore using GraphQL, streamlining the process of displaying Sitecore-managed content in our Next.js front-end.

The useFetchItemFields hook is designed to retrieve specific fields of a Sitecore item. This functionality is particularly useful for developers working with Sitecore as a CMS, enabling them to access and display customized content on their Next.js front-end.

Code breakdown:

export const useFetchItemFields = (sitecorePath: string) => {
  const [itemFields, setItemFields] = useState(null);
  const { sitecoreContext } = useSitecoreContext();
  useEffect(() => {
    const fetchData = async () => {
      try {
        const url =`${process.env.PUBLIC_URL}/api/graphQL/GetItemFields`;

        const response = await fetch(url, {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({
            sitecorePath: sitecorePath,
            sitecoreLanguage: sitecoreContext?.language ?? 'en',
          }),
        });

        if (!response.ok) {
          throw new Error(`HTTP error! Status: ${response.status}`);
        }

        const result = await response.json();

        const resultProps: itemProps = JSON.parse(result);

        setItemFields(resultProps);
      } catch (err) {
        console.error('Error with PageScriptBox:', err);
      }
    };

    fetchData();
  }, [sitecorePath, sitecoreContext?.language]);

  return itemFields;
};

How It Works

  • The hook employs useState for managing the fetched data state (itemFields) and useEffect for handling the data fetching operation. This setup ensures efficient state management and response to component lifecycle events.
  • Utilizing useSitecoreContext, the hook gains access to the current Sitecore context. This is particularly crucial for fetching language-specific content, ensuring users receive content in the correct language.
  • Within useEffect, a fetchData function is defined to conduct the API call. This function is the heart of the hook, where it communicates with the backend, requesting the appropriate content based on the sitecorePath and the language setting from Sitecore’s context.

API Side for Data Fetching

The backend part of this setup involves an API handler that responds to the hook's requests:


export default async function handler(req, res) {

  try {
    const { sitecorePath, sitecoreLanguage } = req.body;

    const categoryDetailDb = await GetItemFields(sitecorePath, sitecoreLanguage);

    return res.status(200).json(JSON.stringify(categoryDetailDb));
  } catch (error) {
    console.error('Error getting Side Nav Data:', error);
    return res.status(500).json(JSON.stringify(error));
  }
}

const GetItemFields = async (sitecorePath: string, sitecoreLanguage: string): Promise<any> => {
  const graphQLClient = new GraphQLClient(config.graphQLEndpoint);
  graphQLClient.setHeader('sc_apikey', config.sitecoreApiKey);

  const pageComponentsQuery = gql`
    query {
      item(
        path: "${sitecorePath}"
        language: "${sitecoreLanguage}"
      )  {
        id
    name
    fields{
      id
      name
      value
    }
      }
    }
  `;

  const data = await graphQLClient.request(pageComponentsQuery);

  return data;
};

Integrating useFetchItemFields in Next.js

Incorporating the useFetchItemFields hook into your Next.js components is straightforward, enabling seamless Sitecore content retrieval:

Example Integration

const MyComponent = () => {
const itemFields = useFetchItemFields('{AAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA}');
// Render logic using the fetched itemFields
  ...
};

This custom hook, along with the API handler, forms a cohesive unit that simplifies fetching and displaying data from Sitecore in a Next.js application. It abstracts the complexities of GraphQL queries and state management, allowing developers to focus more on building the user interface.

Custom Hook: useTranslations for Localization

Continuing our journey to enhance Next.js applications with Sitecore/XM Cloud, let's explore our second custom hook: useTranslations. This hook is pivotal for maintaining an organized and efficient approach to handling translations and localization within your application.

Purpose of useTranslations

Centralized Translation Management

  • The useTranslations hook leverages useI18n from 'next-localization' to handle translations.
  • Its primary role is to provide a centralized place for managing all Sitecore dictionary items. This centralization is key for maintaining consistency and simplicity in the application's translation and localization process.

How It Works

import { useI18n } from 'next-localization';

export function useTranslations() {
  const i18n = useI18n();

  return {
    creditLabel: i18n?.t('CreditLabel'),
    creditsLabel: i18n?.t('CreditsLabel'),
    submitSearchLabel: i18n?.t('SubmitSearchLabel'),
    readMoreLabel: i18n?.t('ReadMoreLabel')
  };
}

How It Works

  • The hook starts by using useI18n to access the internationalization functionalities of the Next.js application.
  • It then defines a set of properties, each corresponding to a specific translation key (like 'CreditLabel', 'CreditsLabel', etc.). The hook fetches these translations from Sitecore's dictionary items, ensuring that the displayed content is appropriately localized.
  • The hook returns an object containing all the required labels and texts. This object can be used throughout your Next.js components for displaying translated content.

Integrating useTranslations in Next.js

First, call useTranslations at the beginning of your component to access the translations object.

const translations = useTranslations();

Then Use the properties of the translations object to display localized text in your component. For instance, if you want to display a breadcrumb home label, you would use translations.readMoreLabel.

<Text>
  {translations.readMoreLabel}
</Text>

Benefits of useTranslations

  • Maintainability: By centralizing the management of all Sitecore dictionary items, useTranslations significantly enhances the maintainability of your codebase.
  • Scalability: It allows for easy scalability by adding new languages or modifying existing translations.
  • Consistency: Ensures consistency in implementing and displaying translations across different components.

This hook is a testament to the power of custom hooks in enhancing not just the functionality but also the organization and maintainability of Next.js applications, especially in multilingual settings.

Closing Thoughts on Next.js Hooks in XM Cloud

In today’s exploration, we’ve unlocked the magic of useFetchItemFields and useTranslations hooks, transforming our Next.js applications in the Sitecore XM Cloud environment. These aren’t just mere tools; they're the essence that makes our apps vibrant, intelligent, and in tune with diverse user needs. It's like giving voice and understanding to our digital creations, all through the simplicity and brilliance of these hooks. And what's exciting is that this is just the start. Keep an eye out for our future posts, where we'll introduce more innovative hooks, each adding a new dimension to our web development adventures. Stay tuned for more!

References

For further information and a deeper understanding of the concepts discussed in this blog, the following resources have been referenced:

  1. React Dev - Reusing Logic with Custom Hooks: An official guide by React explaining the concept and implementation of custom hooks.
  2. Sitecore Helix - Language Support and Dictionary: Detailed documentation on Sitecore's approach to multilingual content management.
  3. Sitecore Documentation - Using GraphQL to Fetch Component-Level Data in JSS Next.js Apps: A guide on leveraging GraphQL in Sitecore for JSS Next.js applications.


Photo of Fishtank employee Sohrab Saboori

Sohrab Saboori

Senior Full-Stack Developer

Sohrab is a Senior Front-End Developer with extensive experience in React, Next.js, JavaScript, and TypeScript. Sohrab is committed to delivering outstanding digital solutions that not only meet but exceed clients' expectations. His expertise in building scalable and efficient web applications, responsive websites, and e-commerce platforms is unparalleled. Sohrab has a keen eye for detail and a passion for creating seamless user experiences. He is a problem-solver at heart and enjoys working with clients to find innovative solutions to their digital needs. When he's not coding, you can find him lifting weights at the gym, pounding the pavement on the run, exploring the great outdoors, or trying new restaurants and cuisines. Sohrab believes in a healthy and balanced lifestyle and finds that these activities help fuel his creativity and problem-solving skills.