David Hockley

Next Js: The app router in practice

When the new app router came out in Next JS, I updated my website to use it. I wanted to understand first-hand how it works. I wanted to understand the changes and whether they are worth the effort.

I’ve already talked about React Server Components in theory. Here I’d like to go through some practical lessons I learnt while coding.

I will focus on the basics: how the app router works. There is much more to cover, such as SEO features, translation, and managing content. I’m splitting that up because I’d like to keep this short, but I will be covering that later.

So here is how the app router differs from the page directory router. Let’s dive in.

The basics of the app directory router

First, as you might know, the app router uses the filesystem in the app directory to link a URL to specific files in the filesystem. That much was also true of the pages folder router.

Let’s start with the basics: Let’s say I have a blog/directory that contains a page.tsx The first thing to note here is that the file is called “page”, and not “index”.

Now, when I navigate to the blog/ path of my website, the component inside the page.tsx file will be rendered. That much is the same as the pages router.

However, in the pages router, you could also route using filenames. For example, you could have an about.tsx that would map to the /about URI. That no longer works in the app router.

Instead of thinking in files and folders, you need to think only in folders.

The app router allows you to have additional specialised files in each directory. These add functionality. For example, I can have a file to manage errors, one for the layout or the loading interface.

Now, what else can the app router do?

Dynamic routes

In my example, the blog folder has a fixed name. However, Next also supports folders and subfolders with dynamic names, which map to dynamic routes. These use the square brackets notation. Allow me to explain with an example.

In my case, the blog/directory has a folder called tag, another called category, and a third one called [slug], between square brackets. This means that blog/tag/will map to the tag subfolder, and blog/category/will map to the category subfolder. But any other path that starts with blog/ will map to the [slug] folder.

When there is a dynamic path, the router passes the values of the parameter to the component in the page.tsx file, using a parasprop.

For example, if we take a look at the page.tsx file in the [slug] folder of my blog folder. Here, the paramsobject contains a slug member (and also a lang member because my website is multilingual).

export default async function BlogPostPage({ params: {lang, slug } }: Params) {

Using the value of the slug and the lang parameters, I can then determine which article has been requested and fetch it:

const post = await findPostBySlug(lang, slug); 

(I won’t go into the details of the findPostBySlugbecause it isn’t specific to the app/router and depends on how you fetch your content)

Managing errors and redirects

404 error management

Of course, if there isn’t any content that matches, I can simply return an error. Since my page is a React Server Component, this is relatively simple: I start by importing the notFound function from next/navigation. Then if I haven’t found the content, I return a call to the function.

import { notFound } from 'next/navigation';  
/* ... */ 
export default async function BlogPostPage({ params: {lang, slug } }: Params) {

	const post = await findPostBySlug(lang, slug); 

	if (!post) {
	  return notFound();
	}

	// here continue as normal 

}

Managing redirects

In my case, I also want to be able to deprecate content and redirect to new pages. How do I go about that?

First, I import the redirect function from next/navigation. Then, if my content has a redirect URL, I redirect to it.

if (post.redirectUrl) {
  redirect(post.redirectUrl);
}

Parenthesis directories

Another point worth mentioning, which caused a bit of confusion for me when I was starting, is that you can also define a directory with a name inside parenthesis.

This helps organise your code but doesn’t impact the routing. So, for instance, if you wanted to group all your e-commerce stuff, you could create a (e-commerce) folder. Then (for example) the (e-commerce)/courses folder would map to the courses/URL (and not to e-commerce/courses).

The router file

There is much more to discover. The documentation is still being written in some cases! One thing I did want to point out, though, was that instead of the page.tsx file, you could instead have a route.ts. This allows you to code lower-level behaviour where you specify exactly what happens when a request hit the route with a specific HTTP verb.

This allows you to write APIs but also non-page content, like an RSS feed.

Now, there is more to cover concerning the app router.

First, its SEO features, how to manage metadata, create sitemaps, and the robots file.

And second, how to translate Next JS websites. Because all my favourite existing libraries use client-side hooks that don’t work in the app directory, so I had to add my own.

Social
Made by kodaps · All rights reserved.
© 2023