In the previous post, We created a BlogPost application rendering content on server-side with Next.js. We will be changing the same application to use SSG (Static Generation) capability of Next.js.
We will create an application which will have index page to list all the available blog links and statically generated blog posts. We will use getStaticProps
and getStaticPaths
functions from Next.js.
getStaticProps
function is called by Next.js at build time and pre-renders the page.
getStaticPaths
function is also called by Next.js at build time. If you are usinggetStaticProps
and there are dynamic paths then you define those ingetStaticPaths
.
index.tsx
.import React from 'react';
import { GetStaticProps, GetStaticPropsContext } from 'next';
import BloggerService from '../service/BloggerService';
import styles from '../App.module.css'
/* Line 1*/ interface IndexPageProps {
blogLinks: Array<{ id: string, title: string }>
}
export default function IndexPage(props: IndexPageProps) {
/* Line 2 */ return (
<div className={ styles['blog-container'] }>
<ul className={ styles['blog-posts'] }>
{props.blogLinks.map(blogLink => <li key={blogLink.id}><a href={`/posts/${encodeURIComponent(blogLink.id)}`}>{blogLink.title}</a></li>)}
</ul>
</div>
);
}
/* Line 3 */ export const getStaticProps: GetStaticProps = async (context: GetStaticPropsContext<any>) => {
const bloggerPosts = await BloggerService.getAllPosts();
const blogLinks = bloggerPosts.posts.map(post => {
const splittedId = post.id.split('-')
return {
id: splittedId[splittedId.length - 1],
title: post.title
}
});
return {
props: {
blogLinks
}
}
}
Explanation
At line 1, we defines the props type expected by IndexPage function.
At Line 2, we are returning
React.Element
. We are iterating on the blogLinks passed as props to this component and returns a list. This property is passed fromgetStaticProps
function at build time.At Line 3, we are defining
getStaticProps
function. We are callingBloggerService
and retrieving blog feeds from https://codefoundry.dev. Then, we are extracting two properties id and title and are returning those from this method.
At the build time, Next.js will call this function on server-side and will pass these properties to IndexPage function and will generate static HTML on server. That static HTML will be served everytime.
[slug].tsx
to catch all the routesNext step is to create [slug].tsx
under pages/posts
folder. This component will catch all the dymaically generated URL and will open the statically generated HTML if found otherwise endup showing 404 page.
import React from 'react';
import { GetStaticPaths, GetStaticProps, GetStaticPropsContext } from 'next';
import IBlogPost from '../../models/IBlogPost';
import BloggerService from '../../service/BloggerService';
import BlogPost from '../../components/BlogPost';
import styles from '../../App.module.css';
/* Line 1 */ interface IServerProps {
post: IBlogPost
}
export default (props: IServerProps) => {
/* Line 2 */ return (
<>
<div className={styles['App-Container']}>
<BlogPost post={props.post} />
</div>
</>
);
}
/* Line 3 */ export const getStaticPaths: GetStaticPaths = async() => {
const bloggerPosts = await BloggerService.getAllPosts();
const paths = bloggerPosts.posts.map(post => {
const splittedId = post.id.split('-')
const slug = splittedId[splittedId.length - 1]
return {
params: {
slug
}
}
});
return {
paths,
fallback: false
}
}
/* Line 4 */ export const getStaticProps: GetStaticProps = async(context: GetStaticPropsContext<any>) => {
const slug = context?.params?.slug ?? 'na'
const bloggerPosts = await BloggerService.getAllPosts();
const post = bloggerPosts.posts.find( post => post.id.endsWith(slug))
return {
props: {
post
}
}
}
Explanation
At Line 1, we are creating type for props this component takes.
At Line 2, we are returning React.Element. We are passing post property from props to BlogPost component. This property is passed by
getStaticProps
function at build time.At Line 3, we are defining
getStaticPaths
function. This function returns the list of dynamic paths this page will handle.At Line 4, we are defining
getStaticProps
function. This function reads the slug property from context's params property. This proeprty is generated bygetStaticPaths
function(Line3) and then get the post from BloggerService and finally this post property is passed to this page (Line 2).
I have modified existing code for this example. Let's cleanup code what is not required.
First, remove unwanted libraries with npm remove @reduxjs/toolkit
, react-redux
, next-on-netlify
command. Remove BlogSearch.tsx
, BlogListing.tsx
, BlogPosts.tsx
and BlogPosts.module.css
from src/components
folder. Remove index.css
and index.tsx
from src
folder. Update _app.tsx
under src/pages
and remove redux store and provider. That's it.
Let's run the application.
Click on any link and you will see statically generated blog page.
That's it :). You can download the full code from Github.
In this post, we introduced getStaticPaths
and getStaticProps
methods of Next.js for Static site generation. We used both methods in [slug].tsx
for dynamic path generation. At last, we removed unwanted files from last code example.
What's next?
- In the next post, we will deploy Next.js project (Static Generation and SSR) on Netlify.