Part 54: Integrating CMS Data into Your Next.js Application: A Practical Guide
[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 devUpdating 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:
Logging Component Renders: Start by adding a console log to monitor when the
ReviewsPagecomponent 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> </> ); }Fetching Data from the CMS: We need to rewrite the
getReviewsfunction to fetch data from the CMS instead of local files. This involves using theqslibrary to construct the query string for the API call.
Writing the API Fetch Logic
Import the
qsLibrary: Ensure that theqslibrary is imported in yourreviews.jsfile:import qs from 'qs';Modify the
getReviewsFunction: 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, })); }Transform the Data: The CMS response contains a
dataarray, each with anattributesobject. We map these into a simpler structure containing only the properties needed by our page component.
Rendering the Reviews
Adapt Data for Rendering: Ensure the data returned by
getReviewsmatches the structure required by your page. For instance, if your page needsslugandtitle, your mapped objects should include these:return data.map(({ attributes }) => ({ slug: attributes.slug, title: attributes.title, }));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