Next - Static Page Generation with a dynamic route that catch all routes

About

An example on how to catch all routes with two parameters.

The below codes belong to one file /pages/exam/[...slug].tsx that will respond to url such as:

where:

  • exam is the directory in page
  • a and b are numerical parameters defined in the slug with the getStaticPaths function

Example Steps

Define the slug with getStaticPaths

The getStaticPaths defines all possible paths and define the slug part as an array.

import { GetStaticPaths } from 'next';
/**
 * The paths returned as argument will be build at build time.
 */
export const getStaticPaths: GetStaticPaths = async () => {
  
  // Define all paths to be pre-render 
  // The slug is an array 
  // The slug name is slug because this is the name of the file `...slug.js`
  const paths = questions
    .map(question => ({
      params: { slug: [question.examId,question.questionId]  },
    }))

  // { fallback: false } means other routes should 404.
  return { paths, fallback: false }
}

Parse the slug, fetch more data and build props with getStaticProps

  • Get the slug,
  • extract the id,
  • [optionally] fetch more data with the id (below we just return the id but with them you could get your data)
  • and return the data as props for the static component
import { GetStaticProps } from 'next';
// This function gets called at build time on server-side.
// It won't be called on client-side, so you can even do
// direct database queries.
export const getStaticProps: GetStaticProps = async ({ params }) => {
  try {
    const slug: string[] = (params?.slug as string[])
    const examenId: number = Number(slug[1]);
    const questionId: number = Number(slug[3]);
    // The props attribute is the argument of the StaticPropsDetail component (ie 
    return {
      props: {
        examen: examenId,
        question: questionId
      }
    }
  } catch (err) {
    return { props: { errors: err.message } }
  }
}

A static component that consume the previous build props

  • The static components
type QuestionProps = {
  examId: number,
  questionId: number,
  errors: string
}

export default function QuestionPage(props: QuestionProps) {

  const { examId, questionId, errors } = props;
  
  if (errors) {
    return (
      <Page title={`Error`}>
        <p>
          <span style={{ color: 'red' }}>Error:</span> {errors}
        </p>
      </Page>
    )
  }
  return (
     <div>
      <h1>Question {questionId} from Exam {examId}</h1>
     </div> 
    
  )
}

Powered by ComboStrap