Routing in Next.js: A Comprehensive Guide to Dynamic Routes and Pre-Rendering

Next.js has revolutionized the way we build React applications by providing a powerful and intuitive framework for server-side rendering, automatic code splitting, file-based routing, API routes, and more. One of the standout features of Next.js is its support for dynamic routes and pre-rendering, which allow you to create pages that are optimized for performance and SEO while still being highly dynamic and personalized.

In this in-depth guide, we‘ll take a close look at how routing works in Next.js, with a focus on setting up dynamic routes and leveraging pre-rendering for maximum efficiency. Whether you‘re new to Next.js or looking to deepen your understanding of its routing capabilities, this article will provide you with the knowledge and practical examples you need to take your Next.js skills to the next level.

How Routing Works in Next.js

Before we dive into dynamic routes, let‘s take a step back and look at how routing works in Next.js compared to a traditional React application.

In a React app, routing is typically handled by a library like React Router, which uses a declarative, code-based approach to define routes and map them to components. Here‘s an example of what that might look like:

import { BrowserRouter as Router, Route } from ‘react-router-dom‘;

function App() {
  return (
    <Router>
      <Route exact path="/" component={Home} />
      <Route path="/about" component={About} />
      <Route path="/contact" component={Contact} />
    </Router>
  );
}

While this approach works well for many applications, it can become cumbersome and difficult to maintain as your app grows in complexity.

Next.js takes a different approach to routing by leveraging the file system to define routes. Instead of writing code to map URLs to components, you simply create a file in the pages directory that corresponds to the desired route.

For example, if you wanted to create a route for /about, you would create a file called pages/about.js and export a React component from it. Next.js will automatically handle the routing for you, no configuration required!

Here‘s what the file structure might look like:

pages/
  index.js
  about.js
  contact.js

This file-based approach to routing has several advantages over the code-based approach used in traditional React applications:

  1. It‘s simple and intuitive. The file structure mirrors the URL structure, making it easy to understand and navigate.

  2. It‘s easy to maintain. Adding a new route is as simple as creating a new file, and removing a route is as easy as deleting a file. No need to update a central configuration file.

  3. It supports dynamic routes out of the box. As we‘ll see in the next section, Next.js makes it trivial to create dynamic routes that can be pre-rendered for optimal performance.

Dynamic Routes in Next.js

One of the most powerful features of Next.js is its support for dynamic routes. A dynamic route is a route that can accept parameters, allowing you to create pages that are customized based on user input or other variables.

To create a dynamic route in Next.js, you simply create a file in the pages directory with square brackets around the parameter name. For example, if you wanted to create a dynamic route for blog posts, you might create a file called pages/blog/[slug].js.

Inside this file, you can access the value of the slug parameter using the useRouter hook from the next/router module. Here‘s an example:

import { useRouter } from ‘next/router‘

function BlogPost() {
  const router = useRouter()
  const { slug } = router.query

  return 
}

export default BlogPost

Now, when a user visits a URL like /blog/my-first-post, Next.js will automatically match the [slug] parameter to the value my-first-post and pass it to the BlogPost component as a prop.

But what if you want to fetch data based on the slug parameter and pre-render the page with that data? That‘s where the getStaticProps and getStaticPaths functions come in.

Pre-Rendering Dynamic Routes with getStaticProps and getStaticPaths

One of the key benefits of Next.js is its ability to pre-render pages for improved performance and SEO. With static site generation (SSG), Next.js can generate HTML pages at build time that can be served to users without requiring any additional server-side rendering.

To pre-render a dynamic route, you need to use two special functions provided by Next.js: getStaticProps and getStaticPaths.

getStaticProps is an async function that runs at build time and fetches the data needed to pre-render a page. It receives a context object as an argument, which contains the params object with the dynamic route parameters.

Here‘s an example of how you might use getStaticProps to fetch blog post data based on the slug parameter:

import { getBlogPost } from ‘/lib/api‘

export async function getStaticProps({ params }) {
  const post = await getBlogPost(params.slug)

  return {
    props: {
      post
    }
  }
}

In this example, we‘re importing a getBlogPost function from a hypothetical API library that fetches a blog post by its slug. We pass the slug parameter from the params object to this function and wait for it to return the blog post data.

Finally, we return an object with a props property that contains the blog post data. This data will be passed to the page component as props and can be used to render the page content.

But how does Next.js know which slug values to generate pages for? That‘s where getStaticPaths comes in.

getStaticPaths is an async function that runs at build time and returns an object with a paths property that specifies which paths should be pre-rendered.

Here‘s an example:

export async function getStaticPaths() {
  const posts = await getAllBlogPosts()

  const paths = posts.map((post) => ({
    params: { slug: post.slug }
  }))

  return { paths, fallback: false }
}

In this example, we‘re importing a hypothetical getAllBlogPosts function that returns an array of all our blog posts. We then use the map function to create an array of objects, each with a params property that specifies the slug parameter for that post.

Finally, we return an object with the paths array and a fallback property. The fallback property specifies how Next.js should handle paths that are not included in the paths array.

If fallback is false, Next.js will return a 404 page for any paths not included in paths. If fallback is true, Next.js will attempt to generate the page on-the-fly using getStaticProps.

Here‘s the complete code for our dynamic blog post route:

import { useRouter } from ‘next/router‘
import { getBlogPost, getAllBlogPosts } from ‘/lib/api‘

function BlogPost({ post }) {
  const router = useRouter()

  if (router.isFallback) {
    return <div>Loading...</div>
  }

  return (
    <div>

      <div>{post.body}</div>
    </div>
  )
}

export async function getStaticProps({ params }) {
  const post = await getBlogPost(params.slug)

  return {
    props: {
      post
    }
  }
}

export async function getStaticPaths() {
  const posts = await getAllBlogPosts()

  const paths = posts.map((post) => ({
    params: { slug: post.slug }
  }))

  return { paths, fallback: false }
}

export default BlogPost

Let‘s break this down:

  1. We import the useRouter hook and our API functions.
  2. We define the BlogPost component, which receives the post data as a prop.
  3. We use the useRouter hook to check if the page is being generated on-the-fly (i.e. if fallback is true and the path was not included in paths). If so, we display a loading message.
  4. We define the getStaticProps function to fetch the blog post data based on the slug parameter.
  5. We define the getStaticPaths function to specify which paths should be pre-rendered based on our list of blog posts.
  6. We export the BlogPost component as the default export.

With this setup, our blog post pages will be pre-rendered at build time for optimal performance and SEO. When a user visits a blog post page, they will be served the pre-rendered HTML, providing a fast and seamless user experience.

Conclusion

Dynamic routes and pre-rendering are two of the most powerful features of Next.js, allowing you to create highly performant and SEO-friendly pages that are customized based on user input or other variables.

By leveraging the file-based routing system and the getStaticProps and getStaticPaths functions, you can easily create dynamic routes that fetch data at build time and pre-render the HTML for optimal performance.

Whether you‘re building a blog, an e-commerce site, or any other type of web application, Next.js provides the tools and abstractions you need to create dynamic, scalable, and performant pages with ease.

Similar Posts