Skip to main content

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

Types

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>
)
}