Part 54: Integrating CMS Data into Your Next.js Application: A Practical Guide

[App] Headless CMS

[App] Headless CMS

When building dynamic web applications, fetching and displaying data efficiently is crucial. If you're using a CMS, such as Strapi, to manage your content, integrating this data into your Next.js application can significantly enhance its functionality. In this post, we'll walk through the process of fetching review data from a CMS and displaying it on a Reviews page, transitioning from a standalone script to a fully integrated solution.

Transitioning from Local Files to CMS Data

Initially, our application loaded review data from local files. Now, we aim to fetch this data from the CMS, ensuring our application is dynamic and content-driven.

Setting Up Your Development Environment

First, ensure your development server is running. You can start it by executing:

npm run dev

Updating the Reviews Page

The goal is to modify the ReviewsPage component to display data fetched from the CMS. Here's how we can achieve that:

  1. Logging Component Renders: Start by adding a console log to monitor when the ReviewsPage component renders and what data it receives:

    export default async function ReviewsPage() {
      const reviews = await getReviews();  // Dynamically fetch reviews
      console.log('[ReviewsPage] reviews:', reviews);
    
      return (
        <>
          <Heading>Reviews</Heading>
          <ul className="flex flex-row flex-wrap gap-3">
            {reviews.map((review) => (
              <li key={review.slug} className="bg-white border rounded shadow w-80 hover:shadow-xl">
                <Link href={`/reviews/${review.slug}`}>
                  <img 
                    src={review.image}  // Dynamic image loading based on slug
                    alt=""
                    width={320}
                    height={180}
                    className="rounded-t"
                  />
                  <h2 className="font-orbitron font-semibold py-1 text-center">
                    {review.title}
                  </h2>
                </Link>
              </li>
            ))}
          </ul>
        </>
      );
    }
  2. Fetching Data from the CMS: We need to rewrite the getReviews function to fetch data from the CMS instead of local files. This involves using the qs library to construct the query string for the API call.

Writing the API Fetch Logic

  1. Import the qs Library: Ensure that the qs library is imported in your reviews.js file:

    import qs from 'qs';
  2. Modify the getReviews Function: Replace the logic of fetching from local files with an API request to your CMS:

    export async function getReviews() {
      const url = 'http://localhost:1337/api/reviews?' + qs.stringify({
        fields: ['slug', 'title', 'subtitle', 'publishedAt'],
        populate: { image: { fields: ['url'] } },
        sort: ['publishedAt:desc'],
        pagination: { pageSize: 6 },
      }, { encodeValuesOnly: true });
    
      console.log('getReviews:', url);
      const response = await fetch(url);
      const { data } = await response.json();
      
      return data.map(({ attributes }) => ({
        slug: attributes.slug,
        title: attributes.title,
      }));
    }
  3. Transform the Data: The CMS response contains a data array, each with an attributes object. We map these into a simpler structure containing only the properties needed by our page component.

Rendering the Reviews

  1. Adapt Data for Rendering: Ensure the data returned by getReviews matches the structure required by your page. For instance, if your page needs slug and title, your mapped objects should include these:

    return data.map(({ attributes }) => ({
      slug: attributes.slug,
      title: attributes.title,
    }));
  2. Display the Reviews: Once the data is fetched and structured, render it on the page. Since we have mapped the data to include title, you can display it directly:

    return (
      <>
        <Heading>Reviews</Heading>
        {reviews.map(review => (
          <ReviewCard key={review.slug} title={review.title} />
        ))}
      </>
    );

Handling Errors and Next Steps

While fetching data from the CMS, you might encounter errors, such as missing data or network issues. Make sure to handle these gracefully, perhaps by displaying a fallback message or loading indicator.

Additionally, you might notice errors in the browser console related to prefetching pages that don't exist locally. This occurs because the slug doesn't match any local files. We'll address this in subsequent updates by fetching detailed review data directly from the CMS.

Conclusion

By fetching review data directly from the CMS, we have made our Reviews page dynamic and content-driven. This setup not only enhances the user experience but also streamlines content management. In the next steps, we'll extend this functionality to include images and additional details, further integrating CMS data into our application. Stay tuned for more updates!

Last updated