Introduction
Routing is a fundamental aspect of any web application, defining how users navigate between different sections. Next.js simplifies routing through its file-system based router, where files within the pages directory automatically become routes. This lesson will deep dive into how Next.js handles routing, including dynamic routes, nested routes, and programmatic navigation. We'll also explore strategies for creating consistent layouts across multiple pages, a common requirement for professional applications, ensuring a unified user experience.
Key Concepts
File-System Based Routing
In Next.js, every .js, .jsx, .ts, or .tsx file in the pages directory becomes a route.
-
pages/index.jsmaps to/. -
pages/about.jsmaps to/about. -
pages/blog/first-post.jsmaps to/blog/first-post.
Dynamic Routes
For pages with dynamic segments (e.g., a blog post with a unique ID), Next.js uses square brackets [] in the filename.
-
pages/posts/[id].jsmaps to/posts/1,/posts/hello-world, etc. Theidbecomes a query parameter accessible viauseRouter(). -
Catch-all routes:
pages/posts/[...slug].jsmatches/posts/a,/posts/a/b,/posts/a/b/c. Theslugwill be an array of strings.
Programmatic Navigation with next/link and useRouter
Next.js provides the <Link> component from next/link for client-side transitions between routes. It pre-fetches pages for a snappier experience. For more complex, programmatic navigation (e.g., after a form submission), you can use the useRouter hook from next/router.
Layouts
While Next.js doesn't have a built-in "layout" file, common patterns involve:
-
Per-page layouts: Wrapping individual page components with a layout component.
-
Global Layouts: Using the
_app.jsfile to apply a layout to all pages. This file overrides the defaultAppcomponent and is ideal for global styles, providers (like context APIs), and shared layouts.
Code Example: Routing and Layout
Consider these files:
jsx // pages/index.js import Link from 'next/link'; import Layout from '../components/Layout';
export default function HomePage() { return ( <Layout> <h1>Welcome to Next.js!</h1> <p>Go to <Link href="/about"><a>About Us</a></Link></p> <p>See <Link href="/posts/123"><a>Post 123</a></Link></p> </Layout> ); }
jsx // pages/posts/[id].js import { useRouter } from 'next/router'; import Layout from '../../components/Layout';
export default function PostPage() { const router = useRouter(); const { id } = router.query;
return ( <Layout> <h1>Post ID: {id}</h1> <button onClick={() => router.push('/')}>Go Home</button> </Layout> ); }
jsx // components/Layout.js export default function Layout({ children }) { return ( <div> <header style={{ background: '#eee', padding: '10px' }}> <nav>My Site</nav> </header> <main style={{ padding: '20px' }}> {children} </main> <footer style={{ background: '#eee', padding: '10px', marginTop: '20px' }}> © 2023 Next.js </footer> </div> ); }
Key Takeaways
-
Next.js uses a file-system based router, where files in
pages/define routes. -
Dynamic routes are created using square brackets (e.g.,
[id].js). -
Use the
<Link>component for client-side navigation anduseRouterfor programmatic control. -
Layouts can be implemented per-page or globally via
_app.jsfor consistent UI.