React (next.js) Router
Introduction
Next.js ver 13 (oct 2022) introduced new router concept - App Router (src/app folder).
Old one is called Pages Router (still works, app router has higher priority on conflict case).
- Folders are used to define routes.
- Route is a single path of nested folders,
- Final element is
page.tsx
(it's like index.html)
Pages
Create page.tsx inside any folder to make route accessible.
Layouts
A layout is UI that is shared between multiple routes. On navigation, layouts preserve state, remain interactive, and do not re-render. Layouts can also be nested.
Layout.tsx component should accept a children prop that will be populated with a child layout (if it exists) or a page during rendering.
export default function DashboardLayout({
children, // will be a page or nested layout
}: {
children: React.ReactNode
}) {
return (
<section>
{/* Include shared UI here e.g. a header or sidebar */}
<nav></nav>
{children}
</section>
)
}
- Only the root layout can contain
<html>
and<body>
tags. - When a layout.js and page.js file are defined in the same folder, the layout will wrap the page.
Metadata can only be defined in the root layout.
import type { Metadata } from "next";
import { Inter } from "next/font/google";
const inter = Inter({ subsets: ["latin"] });
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
};
export default function RootLayout({
children,
}: Readonly<{children: React.ReactNode;}>) {
return (
<html lang="en">
<body className={inter.className}>{children}</body>
</html>
);
}
Linking
<Link>
Component- useRouter hook (Client Components)
- redirect function (Server Components)
- native History API
import Link from "next/link";
export default function Page() {
return <Link href="/dashboard">Dashboard</Link>;
}
Use usePathname() to determine if a link is active. For example, to add a class to the active link, you can check if the current pathname matches the href of the link.
export function Links() {
const pathname = usePathname()
return (
<li>
<Link className={`link ${pathname === '/' ? 'active' : ''}`} href="/">
Home
</Link>
</li>
The useRouter hook allows you to programmatically change routes from Client Components.
'use client'
import { useRouter } from 'next/navigation'
export default function Page() {
const router = useRouter()
return (
<button type="button" onClick={() => router.push('/dashboard')}>
Dashboard
</button>
)
}
Component hierarchy
Next.js provides a set of special files to create UI with specific behavior in nested routes.
- layout
- Shared UI for a segment and its children
- page
- Unique UI of a route and make routes publicly accessible
- loading
- Loading UI for a segment and its children
- not-found
- Not found UI for a segment and its children
- error
- Error UI for a segment and its children
- global-error
- Global Error UI
- route
- Server-side API endpoint
- template
- Specialized re-rendered Layout UI
- default
- Fallback UI for Parallel Routes
Only the contents returned by page.tsx or route.tsx are publicly addressable.
Dynamic routes
A Dynamic Segment can be created by wrapping a folder's name in square brackets: [folderName]
.
Dynamic Segments are passed as the params prop to layout, page, route, and generateMetadata functions.
Catch-all Segments
Dynamic Segments can be extended to catch-all subsequent segments by adding an ellipsis inside the brackets [...folderName]
.
Catch-all Segments can be made optional by including the parameter in double square brackets: [[...folderName]]
.
import Link from 'next/link'
export default function PostList({ posts }) {
return (
<ul>
{posts.map((post) => (
<li key={post.id}>
<Link href={`/blog/${post.slug}`}>{post.title}</Link>
</li>
))}
</ul>
)
}