Design Converter
Education
Developer Advocate
Last updated on Sep 5, 2024
Last updated on Apr 22, 2024
Routing is a critical component of any web application, and in a Next.js app, it's handled with a simplicity and elegance that you'll appreciate. As you begin to explore the world of Next.js, you'll find that the framework's routing capabilities are designed to help you create dynamic and user-friendly web applications with ease.
Dynamic routes in Next.js allow you to create pages that can handle a variety of pathnames, making your app more flexible and powerful. For instance, when you want to display a blog post, you don't want to create a separate page for each post manually. Instead, you can write a single file that will handle all the blog posts, with the path to each post being passed as a query string.
In your pages directory, which is the heart of your Next app, you'll find that creating dynamic routes is as simple as adding square brackets to a file name. For example, to create a dynamic route for a blog post, you would name your file [post].js
. This tells Next.js that this is a dynamic page, and it should prepare to receive a specific post value.
Here's a bit of code to illustrate this:
1// pages/posts/[post].js 2import { useRouter } from 'next/router'; 3 4export default function Post() { 5 const router = useRouter(); 6 const { post } = router.query; 7 8 return ( 9 <div> 10 <h1>{post}</h1> 11 {/* Content of the blog post */} 12 </div> 13 ); 14}
The Next.js Link component is a fundamental building block for navigating between pages in your Next.js app. It enables client-side transitions to different routes defined in your app folder, which results in a faster user experience since the page does not need to be reloaded. This is a key feature for creating a smooth and responsive web application.
When you want to create links in your Next.js app, you'll need to import the Link component from 'next/link'. This component is used in conjunction with the href property to define the destination of the link. It's important to note that the Link component doesn't accept the href attribute directly on itself but rather expects it to be passed to a child component, which is usually an <a>
tag or another HTML element.
Here's an example of using the Link component to navigate to a user's profile page:
1// A component that includes navigation links 2import Link from 'next/link'; 3 4export default function Navigation() { 5 return ( 6 <nav> 7 <Link href="/users/johndoe"> 8 <a>John Doe's Profile</a> 9 </Link> 10 {/* More navigation links */} 11 </nav> 12 ); 13}
In this example, when a user clicks on "John Doe's Profile," the Next.js router will push the new route to the browser's history, and the user will be taken to the /users/johndoe page without a full page refresh.
While the Link component is great for declarative navigation, there are times when you need to navigate programmatically. This is where the Next.js Router comes in, allowing you to control the navigation flow dynamically, such as in response to form submissions or after certain user actions.
The router.push function is a method provided by the Next.js Router that allows you to perform client-side navigation similar to the Link component, but it can be triggered from any part of your code. This is particularly useful when you need to redirect a user after an event, like a successful login or form submission.
To use router.push, you'll first need to import the useRouter hook from next/router. Then, you can call router.push with the desired URL as an argument. Here's an example of how you might use router.push to navigate to a different page:
1import { useRouter } from 'next/router'; 2 3export default function LoginButton() { 4 const router = useRouter(); 5 6 const handleLogin = async () => { 7 // Perform login logic... 8 // If successful, redirect to the user's dashboard 9 router.push('/dashboard'); 10 }; 11 12 return ( 13 <button onClick={handleLogin}>Log In</button> 14 ); 15}
In this example, when the user clicks the "Log In" button, the handleLogin function is called, which, upon successful login, uses router.push to navigate to the /dashboard route.
Next.js API routes provide a solution for building your API with Node.js within a Next.js app. This feature allows you to create server-side API endpoints as part of your Next.js application, and it's as simple as creating a file in the pages/api directory. These API routes can then be accessed by your application or by external clients.
To create an API endpoint in Next.js, you start by adding a new file to the pages/api directory. Each file inside this directory is treated as an API route and becomes a serverless function that you can deploy and run on platforms like Vercel.
Here's an example of how to construct a simple API endpoint with a JSON response.:
1// pages/api/hello.js 2export default function handler(req, res) { 3 res.status(200).json({ message: 'Hello from Next.js!' }); 4}
In this example, when a client sends a request to /api/hello, the function inside the hello.js file will execute, and the server will respond with a JSON object containing a greeting message.
Security is a critical aspect of web development, and Next.js provides several mechanisms to help you secure your applications. Protecting routes and implementing role-based access control (RBAC) are two common security measures that can be applied to ensure that sensitive pages and APIs are only accessible to authenticated and authorized users.
Protected routes are those that require a user to be authenticated before they can access them. In a Next.js app, you can implement protected routes by creating a higher-order component (HOC) or using hooks that check for user authentication and redirect unauthenticated users to a login page.
Here's a conceptual example of how you might protect a route using a simple HOC that checks for user authentication:
1import { useRouter } from 'next/router'; 2import { useEffect } from 'react'; 3 4// This could be replaced with an actual authentication check 5const isAuthenticated = () => { 6 // Check if the user is authenticated (e.g., check for a valid session or token) 7 return false; // Let's assume the user is not authenticated for this example 8}; 9 10export function withAuth(Component) { 11 return function AuthenticatedComponent(props) { 12 const router = useRouter(); 13 14 useEffect(() => { 15 if (!isAuthenticated()) { 16 // If the user is not authenticated, redirect to the login page 17 router.push('/login'); 18 } 19 }, [router]); 20 21 // Render the component only if the user is authenticated 22 return isAuthenticated() ? <Component {...props} /> : null; 23 }; 24} 25 26// Usage: Wrap your component with the `withAuth` HOC 27// export default withAuth(MyProtectedPage);
In this example, the withAuth HOC checks if the user is authenticated using the isAuthenticated function. If the user is not authenticated, it redirects them to the login page using router.push.
Next.js offers a robust routing system out of the box, but sometimes you need more control over the routing behavior. Customizing routes allows you to define how requests to certain paths are handled, which can be essential for implementing advanced features or integrating with external systems.
Custom routes in Next.js can be created using redirects and rewrites in your next.config.js file. Redirects are used to map a request to a different destination path, while rewrites modify the request path without changing the browser's URL.
Here's an example of how to create a custom route using redirects in next.config.js:
1module.exports = { 2 async redirects() { 3 return [ 4 { 5 source: '/old-blog/:slug', 6 destination: '/new-blog/:slug', 7 permanent: true, 8 }, 9 ]; 10 }, 11};
In this example, any request to /old-blog/:slug will be redirected to /new-blog/:slug. The permanent: true property indicates that this is a 301 redirect, which is helpful for SEO when you've moved a page permanently.
Advanced navigation techniques in Next.js allow you to create a more polished user experience by handling edge cases like non-existent routes and optimizing your application's routing strategy.
A 404 page is displayed when a user tries to access a page that doesn't exist. Next.js provides a default 404 page, but you can create a custom 404 page to maintain the look and feel of your app and provide a better user experience.
To create a custom 404 page, simply add a 404.js file in the pages directory. This file should export a React component that will be rendered when a page is not found.
Here's an example of a simple custom 404 page:
1// pages/404.js 2export default function Custom404() { 3 return ( 4 <div> 5 <h1>404 - Page Not Found</h1> 6 <p>Oops! The page you are looking for has disappeared into the ether.</p> 7 </div> 8 ); 9}
This custom 404 page will automatically replace the default Next.js 404 page and will be displayed whenever a user navigates to a route that doesn't match any existing page.
Redirects and rewrites are two powerful features provided by Next.js to control the flow of your application's routing. Redirects are used to send users from one route to another, while rewrites allow you to map incoming requests to different destination paths without changing the URL in the browser.
To configure redirects and rewrites, you'll need to edit your next.config.js file. Here's an example of how to set up both:
1module.exports = { 2 async redirects() { 3 return [ 4 { 5 source: '/old-route', 6 destination: '/new-route', 7 permanent: true, // This is a 301 redirect 8 }, 9 ]; 10 }, 11 async rewrites() { 12 return [ 13 { 14 source: '/rewrite-me', 15 destination: '/api/hello', // The user's URL remains the same 16 }, 17 ]; 18 }, 19};
In this example, any request to /old-route will be redirected to /new-route with a 301 status code, indicating a permanent redirect. On the other hand, a request to /rewrite-me will be internally rewritten to /api/hello, but the user's browser will still show the original URL.
Even with a powerful and flexible routing system like Next.js, you may encounter issues that can hinder the user experience or development process. One such issue is the 'next/router was not mounted' error, which can occur in certain situations when using the Next.js Router.
The 'next/router was not mounted' error typically occurs when you try to use the router before it's ready. This can happen, for example, if you attempt to navigate within a component's constructor or during server-side rendering, where the router instance is not yet available.
To resolve this error, ensure that you're only using the router when it's guaranteed to be mounted. This usually means waiting until the component has mounted on the client side. The useEffect hook is a common place to perform client-side navigation, as it runs after the component has rendered and mounted:
1import { useEffect } from 'react'; 2import { useRouter } from 'next/router'; 3 4export default function MyComponent() { 5 const router = useRouter(); 6 7 useEffect(() => { 8 // Perform navigation or other router-related tasks here 9 router.push('/some-path'); 10 }, [router]); 11 12 return ( 13 <div> 14 {/* Component content */} 15 </div> 16 ); 17}
In this example, the navigation action is safely placed inside a useEffect hook, ensuring that the router is mounted and ready to be used.
Routing is a cornerstone of any Next.js application, providing the means to navigate between pages, handle dynamic content, secure routes, and customize navigation to suit your needs. Throughout this exploration of Next.js routing, we've covered a range of topics from dynamic routing and the Link component to API routes, security with protected routes and RBAC, and custom routing techniques
By understanding these concepts and leveraging the full capabilities of Next.js routing, you can create seamless, efficient, and secure user experiences.
Tired of manually designing screens, coding on weekends, and technical debt? Let DhiWise handle it for you!
You can build an e-commerce store, healthcare app, portfolio, blogging website, social media or admin panel right away. Use our library of 40+ pre-built free templates to create your first application using DhiWise.