Mastering Data Fetching in Next.js: A Comprehensive Guide
What is Next.js?
Next.js is a popular React framework that enables you to build highly dynamic applications with ease. It offers a range of features, including prerendering, zero configuration, and hot code reloading.
Getting Started with Strapi
Strapi is an open-source, headless CMS that allows you to build APIs and manage website content easily. It’s 100% JavaScript, fully customizable, and developer-first.
To follow along with this tutorial, you’ll need a basic understanding of asynchronous JavaScript, React, and Node.js.
Setting Up the Project
To begin, create a new directory for your project and install Strapi globally using the command:
npm install -g @strapi/strapi
Then, create a new Strapi app in a folder called backend using the command:
npx strapi new backend --quickstart
This will set up a new Strapi app with SQLite as the database.
Creating the Genres Endpoint
To create a new endpoint, navigate to the Strapi dashboard and click on “Content-Type Builder” in the sidebar. Then, create a new collection type called “genre” and add a text field. This will create a new endpoint for genres.
Creating the Movies Endpoint
Follow the same steps to create a new endpoint for movies. This time, add more fields, including a relation field to connect movies to genres.
Adding Data to the Database
To add data to the database, select any of the APIs on the sidebar, click “Add new,” and fill in the details. You can add data to both the genres and movies endpoints.
Roles and Permissions
By default, Strapi creates six endpoints for each API. To expose these endpoints to the public, navigate to Roles and Permissions > Public > Permissions and check the find and findOne endpoints for both genres and movies.
Consuming Data on the Frontend
Now that we’ve set up the backend, let’s move on to the frontend. Create a new Next.js app in a folder called frontend using the command:
npx create-next-app frontend
Then, install Tailwind CSS using the command:
npm install tailwindcss
Setting Up Environment Variables
Create a .env.development
file at the root of the frontend folder and add the following snippet:
NEXT_PUBLIC_BASE_URL=http://localhost:1337
This will enable you to access this variable with process.env.NEXT_PUBLIC_BASE_URL
.
Making Asynchronous Requests
Create a utils.js
file in the frontend folder and add a utility function to handle all your fetch requests. This function will accept a path and optional params and return some data.
export async function fetchAPI(path, params = {}) {
const res = await fetch(`${process.env.NEXT_PUBLIC_BASE_URL}${path}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
...params,
});
return res.json();
}
The Layout Component
Create a Layout.js
file in the components folder and add a new component that accepts three props. This component will wrap around your pages with a shared header and some meta tags.
import Head from 'next/head';
function Layout({ children, title, description }) {
return (
{children}
);
}
export default Layout;
Server-Side Rendering on the Homepage
Let’s demonstrate server-side rendering (SSR) on the homepage using the getServerSideProps
function. This function will fetch all the movies from the backend and return them as props.
import fetchAPI from '../utils';
export async function getServerSideProps() {
const movies = await fetchAPI('/movies');
return {
props: {
movies,
},
};
}
Statically Rendering the Single Movie Page
To statically render the single movie page, we’ll use the getStaticProps
and getStaticPaths
functions. These functions will fetch a single movie and return it as props, and define all the paths that need to be generated at build time.
import fetchAPI from '../utils';
export async function getStaticProps({ params }) {
const movie = await fetchAPI(`/movies/${params.id}`);
return {
props: {
movie,
},
};
}
export async function getStaticPaths() {
const movies = await fetchAPI('/movies');
return {
paths: movies.map((movie) => ({
params: {
id: movie.id,
},
})),
fallback: false,
};
}
Building the Genres Page
To build the genres page, we’ll repeat what we did on the homepage and the single movie page. We’ll fetch all the genres from the backend and render them on the page.
Statically Rendering the Single Genre Page
To statically render the single genre page, we’ll use the getStaticProps
and getStaticPaths
functions again. These functions will fetch a single genre and return it as props, and define all the paths that need to be generated at build time.
import fetchAPI from '../utils';
export async function getStaticProps({ params }) {
const genre = await fetchAPI(`/genres/${params.id}`);
return {
props: {
genre,
},
};
}
export async function getStaticPaths() {
const genres = await fetchAPI('/genres');
return {
paths: genres.map((genre) => ({
params: {
id: genre.id,
},
})),
fallback: false,
};
}