Routing in NextJS
One of the advantages of using the next.js react framework is because of its easy routing system which takes place without the use of a third-party library, instead routing in next.js is a file-based router which is built on a concept of pages.
Basic Routing
Every nextjs project has a “pages” folder in the project structure, this folder (pages) serves as a container for all our routes. That is, any file created in the “pages” folder automatically functions as a route in your project.
For example:
If we create two files (Home, Blog) in our “pages” folder.
These two files will become routes for our project if we start our server using
yarn dev
// or
npm run dev
In our home/index.js file
function Home() {
return <h1>Home Page</h1>;
}
export default Home;
In our blog.js file
function Blog() {
return <h1>Blog Page</h1>;
}
export default Blog;
💡 Now if we open our browser on localhost:3000
We should see the Home Page
💡 If we navigate to localhost:3000/blog
We should see the Blog Page
So remember that “pages” are associated with their file names.
Now let’s look at the concept of Nested Routing
Nested Routing
Now since we have a blog page on our website, it’ll make sense for us to be able to navigate to each of these blog posts, right? But how do we implement this routing with nextjs?
Well, nextjs makes it very simple to implement nested routes by simply allowing nesting folders inside the “pages” folder.
So to do this we create a folder named “blog” and inside the blog folder, we’ll create two files called first and second, which will be the route to our first blog post and second blog post respectively.
💡 So inside pages > blog > first.js
function First() {
return <h1>First Blog Post</h1>;
}
export default First;
💡 Inside pages > blog > second.js
function Second() {
return <h1>Second Blog Post</h1>;
}
export default Second;
Now if we go into our browser and navigate to localhost:3000/blog we should see Blog Page on the screen
Then if we go to localhost:3000/blog/first we should see First Blog Post
And if we’re on localhost:3000/blog/second we should then see Second Blog Post
But if we look carefully at our “pages” folder we have two items named blog one is a folder and the other is a file, wouldn’t it be better if we can group these two?
Well, with nextjs it’s possible, so let’s do it
💡 Inside the pages > blog
We’ll create a file named “index.js”, then we copy the content inside our blog.js file and paste it inside our pages > blog > index.js
file.
// Inside index.js
function Blog() {
return <h1>Blog Page</h1>;
}
export default Blog;
Now if we open the browser and navigate to localhost:3000/blog, localhost:3000/blog/first, or localhost:3000/blog/second we should still see the same result as we had earlier, but I’m sure here you’ve got a question.
If you remember when you were learning HTML, whenever you opened up the live server your indes.html file gets served to the internet first because it’s the root directory of your project right? Well, the same happens in the nextjs routing system, the index.js file serves as the root/default file inside our folder.
Our index.js inside your blog folder will take the folder name “blog” and use it as our root route for that folder.
So we understand the concept of Nested routing, let’s see how we can route pages dynamically.
Dynamic Routing
So we successfully implemented our nested routes for our blog posts, but what if we have up to a hundred blog posts on our website, do we have to create a hundred files for each post? Nah, that will be too tedious I might give up on the way, but with nextjs, we only need to create 1 file for all our blog posts, yeah you heard me right just one file.
Under this concept will be taking a look at our first nextjs hook useRouter. So let’s dive into it.
So let’s say we’re having 100 blog posts, and we need to dynamically route to each of them firstly
💡 Inside our pages > blog
We will delete the first.js and second.js files
Then we will modify our
💡 blog > index.js
function Blog() {
return (
<>
<h2>Blog post 1</h2>
<h2>Blog post 2</h2>
<h2>Blog post 3</h2>
</>
);
}
export default Blog;
then we will create our dynamic route inside our blog folder like so:
💡 blog > [id].js
Yes, our folder name is [id].js, nextjs allows us to create dynamic paths by wrapping an identifier for our path, in our case the ID **for each post inside a squared bracket [].
Now, inside our dynamic file, let’s write this code then I’ll explain
import { useRouter } from "next/router";
function PostDetails() {
const router = useRouter()
const id = router.query.id
return <h1>Details about blog post {id}</h1>;
}
export default PostDetails;
On the first line, we have our import statement to import the useRouter hook inside our nextjs app.
On line 4 we can see that our useRouter hook returns an object called a router, this router object consists of different options to use for our routing system.
We will be using the query option for this project, the query string parsed to an object, including dynamic route parameters. It will be an empty object during prerendering if the page doesn't use Server-side Rendering. Defaults to {}
What this simply means is that – our query option will return any string that is inserted into our route. Let’s open our browsers, so we can understand how this works.
If we navigate to localhost:3000/blog we should see the list of our blog posts, if we then navigate to localhost:3000/blog/1 we should see on our browser “Details about blog post 1”, so what our router.query function does is to return the “id” we passed dynamically to our route and in our case “id” Now if we try to go to localhost:3000/blog/100 we get the details about our 100th blog post, isn’t this awesome, just with one file we have access to a hundred other files, this is the power of nextjs.
Next, let’s understand the concept of Nested Dynamic Routes
Nested Dynamic Routes
As we build complex applications, it is common to come across the need for a nested dynamic route system.
Building on our already existing project, let’s see how we can introduce a nested dynamic route system. Let’s say for every of our blog posts, a user is able to make a review which we might want to go through and either like or comment on it. If 80 users make a review on our blog post because our article was fascinating, now to view each and every of that review we need to dynamically route to them i.e., our routes will look like this:
💡 localhost:3000/blog/1/reviews/1
which will display to us the first review made on our first blog post. How do we implement this in our project?
First, let’s create a dynamic folder in our blog folder, and then an index.js file inside the dynamic folder:
💡 pages > blog > [id] > index.js
Our index.js file will serve the same purpose as our [id].js file in the last example, so copy the content inside the [id].js file and paste it inside the index.js file, then delete the [id].js file.
import { useRouter } from "next/router";
function PostDetails() {
const router = useRouter()
const id = router.query.id
return <h1>Details about blog post {id}</h1>;
}
export default PostDetails;
Now we have to nest our reviews folder inside our [id] dynamic folder and our index.js file inside our reviews folder.
So let’s create that:
💡 pages > blog > [id] > reviews > index.js
Inside our index.js file, let’s write some code which will display all reviews for our dynamic blog post:
function Review() {
return (
<>
<h2>Review 1</h2>
<h2>Review 2</h2>
<h2>Review 3</h2>
</>
);
}
export default Review;
Lastly, let’s create a dynamic route, so we can dynamically route to each review
To create a dynamic route folder [reviewId] inside the reviews folder and then an index.js file inside the [reviewId] dynamic folder:
💡 pages > blog > [id] > reviews > [reviewId] > index.js
now let’s write some code inside our file:
import { useRouter } from "next/router";
function ReviewDetails() {
const router = useRouter();
const { id, reviewId } = router.query;
return (
<h1>
Review {reviewId} for blog post {id}
</h1>
);
}
export default ReviewDetails;
We’re extracting ID and reviewId from the router.query.
Now if we open our browser and navigate to localhost:3000/blog/1/reviews/1 we should see in our browser “Review 1 for blog post 1”. If you go to localhost:3000/blog/5/reviews/100 you should see “Review 100 for blog post 5”.
Link Component Navigation
Before now, we’ve been navigating to several pages by tweaking the URL inside of clicking on a link to take us to several pages like we would on a real website. So in this section, let’s add links to take us to these various pages.
Nextjs provides us with a “” tag, which functions like the traditional anchor tag for creating links to external/internal links.
So, let’s see how to include that in our project.
Firstly, let’s add a link to our blog page from our home page, so navigate to:
💡 pages > index.js
Write this code inside:
import Link from "next/link";
function Home() {
return (
<>
<h1>Home Page</h1>
<Link href="/blog">
<a>Blog</a>
</Link>
</>
);
}
export default Home;
Now we have a link to navigate to our blog pages.
Let’s make some changes to your blog.js code too:
💡 pages > blog > index.js
write this code inside:
import Link from "next/link";
function Blog() {
return (
<div style={{display: 'flex', flexDirection: 'column'}}>
<Link href='/'>
<a>Go Home</a>
</Link>
<Link href='/blog/1'>
<a>Blog post 1</a>
</Link>
<Link href='/blog/2'>
<a>Blog post 2</a>
</Link>
<Link href='/blog/3'>
<a>Blog post 3</a>
</Link>
</div>
);
}
export default Blog;
With this we’ve learnt basically all the basics of routing in Nextjs, we learnt the concept of nextjs file-based routing system, we created nested routes, dynamic routes, nested dynamic routes and also learnt how to use the inbuilt useRouter hook and also the next/link package from nextjs.
I hope you enjoyed it, looking forward to your questions and contributions. Thank you.