Next.js 路由系統 (App Router)

Next.js 的路由系統是建立在「檔案架構」之上的。在 App Router 模式中,目錄的層級直接映射到 URL 的路徑。這種設計非常直觀,讓你一眼就能看出網站的地圖。

基礎路由定義

app 資料夾中,每個資料夾代表一個 路由分段 (Route Segment),而路徑則是從根目錄開始累積的。

  • 要讓一個路徑可以被存取,該資料夾下必須包含一個 page.tsx

範例:

URL 路徑檔案路徑
/app/page.tsx
/aboutapp/about/page.tsx
/blog/first-postapp/blog/first-post/page.tsx
// app/about/page.tsx
export default function AboutPage() {
  return <h1>關於我們</h1>;
}

巢狀路由 (Nested Routes)

你可以隨意深度的巢狀資料夾來建立複雜的路徑。

例如一個電商網站的分類頁面: app/shop/electronics/page.tsx 會對應到 /shop/electronics

路由預讀 (Prefetching)

Next.js 有一個非常迷人的功能:自動預讀 (Automatic Prefetching)

當一個 <Link> 元件出現在使用者的視窗中(Viewport)時,Next.js 會在背景自動下載該路由的程式碼和初始內容。

  • 這意味著當使用者點擊連結時,跳轉幾乎是瞬發的,因為內容已經存在於快取中。
import Link from 'next/link';

export default function Navigation() {
  return (
    <nav>
      <Link href="/">首頁</Link>
      <Link href="/about">關於</Link>
      {/* 你可以手動關閉預讀 */}
      <Link href="/heavy-page" prefetch={false}>
        負載較重的頁面
      </Link>
    </nav>
  );
}

路由群組 (Route Groups)

有時候你希望把資料夾組織起來,但不希望這些資料夾的名稱出現在 URL 路徑中。這時可以使用括號 (folderName) 來建立路由群組。

路由群組的主要用途有兩個:開發者專案組織佈局共享隔離

邏輯組織 (Project Organization)

當你的專案變大時,可以利用群組將相關的路由放在一起,而不影響 URL。例如將所有身分驗證相關的頁面歸類在 (auth) 資料夾:

  • app/(auth)/login/page.tsx → URL 是 /login
  • app/(auth)/register/page.tsx → URL 是 /register

這樣在檔案管理上會非常整潔,但對使用者來說 URL 依然簡短。

不同區域共享不同 Layout

這是 Route Groups 最強大的地方。你可以為特定的群組定義專屬的 layout.tsx,而不會影響到其他群組。

例如,你希望「行銷頁面」有導覽列,但「後台管理」需要側邊攔:

app/
├── (marketing)/
│   ├── layout.tsx      // 包含 Navigation & Footer
│   ├── about/
│   │   └── page.tsx    // URL: /about (套用行銷 Layout)
│   └── page.tsx        // URL: / (套用行銷 Layout)
└── (dashboard)/
    ├── layout.tsx      // 包含 Sidebar & Admin Header
    └── settings/
        └── page.tsx    // URL: /settings (套用管理 Layout)

建立多重根佈局 (Multiple Root Layouts)

如果你想讓網站的各個部分擁有完全不同的外觀(例如 <html><body> 標籤都不同),你可以刪除最外層的 app/layout.tsx,並在每個路由群組中各放一個。

當你使用多重根佈局時,在不同群組之間切換會導致「整頁重新整理」(Full Page Reload),因為底層的 HTML 結構已經徹底改變了。

私有資料夾 (Private Folders)

如果你想在路由目錄下放置組件或測試檔案,但不想讓它變成路徑,可以使用底線前綴 _folderName

  • app/_components/Button.tsx:這不會變成路徑,即使裡面有 page.tsx 也會被忽略。

編程導航 (Programmatic Navigation)

除了 <Link>,有時你需要在程式邏輯中切換路由(例如登入成功後跳轉)。這時可以使用 useRouter 鉤子。

useRouter 必須在 Client Component 中使用。
'use client';

import { useRouter } from 'next/navigation';

export default function LoginForm() {
  const router = useRouter();

  const handleLogin = () => {
    // 執行登入邏輯...
    router.push('/dashboard');
  };

  return <button onClick={handleLogin}>登入</button>;
}

理解了基礎路由後,我們接下來要討論如何讓這些頁面共享共同的結構,也就是 Layouts。