How to use getStaticPaths on dynamic routes in Next.js

What is getStaticPaths?

getStaticPaths is another special function in Next.js used in conjunction with getStaticProps for dynamic routes. In other words, you can use getStaticPaths on a page that uses a dynamic route, and whenever you use this function on that page, there must be a getStaticProps function as well.

[sample].js

The blocks diagram of a page on dynamic route

What is a Master-Detail UI pattern ?

Imagine you are developing a website with the following user interfaces. You may have seen this pattern many times when you browse the web. This UI pattern is called the Master-Detail pattern.

 

Master-Detail UI

in this post, I am going to display a list of US presidents on the master page, and on the details page, I will show some facts about each president.

Implementing a Master-Detail UI in Next.js

Note: If you are new to Next.js, please learn how to set up a Next.js project and Next.js routing

  1. Open the terminal and run npx create-next-app demo-next-app
  2. Open the project folder in your favorite editor 
  3. We are going to create the main page ( master UI ) on the localhost:3000/presidents. Therefore, in the pages folder, create another folder named “presidents
  4. Inside the “presidents” folder, create a file: index.js, and add the code below to it. 
import Link from 'next/link';

function PresidentList( { presidents }){
    return( 
        <>
            <p>List of US presidents</p>
            {
                presidents.map( 
                    president =><div key={ president.id }>
                        
                        <Link href= { `presidents/${president.id}`}>
                            <li><a>{ president.name }</a></li>
                        </Link></div>
                 
                 )
            }
        </>
    )
}

export default PresidentList
 
 
export async function getStaticProps(context){

        const response = await fetch('https://api.sampleapis.com/presidents/presidents',{
            method:'GET',
            headers:{
                'Content-Type':'application/json'
            }
        });
        const data = await response.json();
        
        return {
            props:{
                presidents: data.slice(0,3),//take only 3 names from the list
            },
        }
}
  1. This code uses getStaticProps. I have a post on getStaticProps that explain getStaticProps and the code below.
  2. When a user clicks on a name of a president, we need to display the details about that president on the details page. For this reason, we need to have a dynamic route. The route will be localhost:3000/president/presidentId.
  3. presidentId is a dynamic parameter. Its value is determined when the user clicks on the name of the president. 
  4. Now, create another file in the president’s folder. This time name it as [presidentId].js,and add the following code to it.
  5. There are three functions in this file: 
    1. getStaticProps(context)
    2. getStaticPaths()
    3. President({ president })
function President( { president }){  

    return( 
        <>
            <h1>President : { president.name }</h1>
            {
                 
             <div>
                <label>Years in office: </label>{ president.yearsInOffice }<br />
                <label>Vice president: </label>{ president.vicePresidents }<br />
                <img src={ president.photo } />
             </div>
                 
            }
        </>
    )
}

export default President

export async function getStaticPaths(){
    return {
        paths:[
            { params:{ presidentId: '1' }  },
            { params:{ presidentId: '2' }  },
            { params:{ presidentId: '3' }  }
        ],
        fallback:false
    }
}

 
export async function getStaticProps(context){
    const { params } = context;
    console.log( context)
    const response = await fetch(`https://api.sampleapis.com/presidents/presidents/${ params.presidentId }`,{
        method:'GET',
        headers:{
            'Content-Type':'application/json'
        }
    });
    const data = await response.json();
   
    return {
        props:{
            president: data,
        },
    }
}

getStaticProps with a context parameter

getStaticProps function that so far we have seen had no parameter. But, it can take a parameter. The term “context” is used in convention, but you can use any appropriate name.

export async function getStaticProps(context) {
  return {
    props: {}, 
  }
}

A context is an object with key-value pairs. It has the params, preview, previewData, locale, locales, and defautLocale as the keys. For our example, we are going to utilize the params key. 

Params key contains the route parameters of the dynamic route. For example, [presidentId].js is in the form of params: { presidentId: … }. The value of presidentId depends on the user’s choice from the list of names.

getStaticPaths for pages on dynamic routes

As mentioned before, we need getStaticPaths on a page that uses a dynamic route. If you do not this function, a run-time error will generate.

Error: getStaticPaths is required for dynamic SSG pages and is missing for ‘/presidents/[presidentId]’. Read more: https://nextjs.org/docs/messages/invalid-getstaticpaths-value

Unlike getStaticProps, getStaticPaths runs only at the build time. It returns an object with the two required properties: paths and fallback.

paths property

This property determines which path should be pre-rendered. Its value is an array of objects. Each object has a params property, which itself is another object. This object has the key ‘presidentId’ which is the parameter used in the dynamic route. Notice that the value of presidentId is a string.

In the above code, I have only three elements in the array. Therefore, I can hard-code the parameters to match the presidentId. But, what if you have a large number of items. It is not practical to hard-code all the values. 

Depending on the logic of your application, the method you would get the ids can be different. In this example, I am going to make an API call and iterate through the array of objects to get the ids. 

export async function getStaticPaths(){
    const response = await fetch('https://api.sampleapis.com/presidents/presidents',{
            method:'GET',
            headers:{
                'Content-Type':'application/json'
            }
        });
   
    const data = await response.json();
   
    //creating an array of objects
    const paths = data.map( president => {
            return {
                params :{ presidentId: `${president.id }`}
           
            }
        }
           
    )

 
    return {
        paths,
        fallback:true
    }
}

Note: You need to make another change in president/index.js so that you will see all the names of the presidents on the master page. 

Modify the code in getStaticProps in this file in the return statement as below. 

return {
            props:{
                presidents: data,//slice method has been removed
            },
        }

fallback property 

This property can take 3 values: false, true, and blocking. How getStaticProps runs changes based on this property.

fallback: falsefallback: truefallback:’blocking’
For the paths specified in the Paths propertyThe paths returned from getStaticPaths will be rendered to HTML at build time by getStaticProps.The paths returned from getStaticPaths will be rendered to HTML at build time by getStaticPropsThe paths returned from getStaticPaths will be rendered to HTML at build time by getStaticProps
For the paths not specified in the Paths propertyGenerate a 404 pageServe a “fallback” version of the page on the first request. In the background, HTML and JSON files are statistically generated relevant to the newly requested path, which means getStaticProps runs during this period.Server-side rendering(SSR) on the first request & send the response as HTML. The getStaticProps runs before the initial rendering.
As a response from the server, the browser receives the JSON for the generated path. Next.js utilize this file to render the page with the required props. 

A user will notice an automatic transition from a “fallback”  page to the full page(the page with props) on the browser.
When complete, the browser receives the HTML for the generated path. The user might experience a small delay in rendering the full page requested, but, there is no loading/fallback state during this period. 
A subsequent request to the path will handle just like other pre-rendered pages at the build time.A subsequent request to the path will handle just like other pre-rendered pages at the build time.
When to useSimple applications with a limited number of paths to pre-render.

When you do not need to add new pages to your site.
For apps with a large number of static pages. This will save time in creating pages in the build time.For apps with a large number of static pages.

If the customer does not a loading indicator message until the actual page they need is rendered.

President function:  the React component

This is a regular React function responsible for displaying the output. It will use the president prop returned by the getStaticProps. You need to do some modification to the code in this function when the fallback property in getStaticPaths is true.

Handling Error When fallback: true

When you run the next build when the fallback is true, you will get a Build error if you do not handle the condition when the page props are not yet available. You can modify the code in function President in [presidentId].js to handle this condition.

import { useRouter } from "next/router"; //add this line

function President( { president }){
    const router = useRouter(); //add this line

    if( router.isFallback ){			 //add this line 
        return <h2>The Page is loading...</h2>	 //you can add any styles or have a custom page
    }
   
    return(
        <>
            <h1>President : { president.name }</h1>
            {
                 
             <div>
                <label>Years in office: </label>{ president.yearsInOffice }<br />
                <label>Vice president: </label>{ president.vicePresidents }<br />
                <img src={ president.photo } />
             </div>
                 
            }
        </>
    )
}

Summary

  • Use getStaticPaths on pages on dynamic routes
  • getStaticPaths run only at build time
  • It must be used with getStaticProps
  • getStaticPaths returned an object with two properties: paths & fallback
  • Paths property determines the path to be pre-rendered
  • The behavior of the getStaticProps changes based on the fallback property

Related Post

Leave a Reply

Your email address will not be published.