App Router 基礎
App Router 是 Next.js 13 之後的路由架構,核心規則很單純:app/ 底下的資料夾路徑,就是網址路徑。每個資料夾要有一個 page.tsx 才會變成可以造訪的頁面,其他幾個特殊檔名則負責 Layout、載入畫面與錯誤處理。
基本概念
app/
├── page.tsx # /
├── about/
│ └── page.tsx # /about
└── blog/
├── page.tsx # /blog
└── [slug]/
└── page.tsx # /blog/任意文章代號
只有資料夾裡有 page.tsx,這個路徑才會真的變成一個頁面;沒有 page.tsx 的資料夾只是路徑的一部分,不會產生對應網址(常用來做元件、共用邏輯的分類)。
特殊檔案慣例
App Router 用固定檔名代表特定角色,這些檔案可以在任何路由層級出現:
| 檔名 | 用途 |
|---|---|
page.tsx |
該路徑的頁面內容,必須有這個檔案才會產生網址。 |
layout.tsx |
該層級與所有子路由共用的外框,切換頁面時 Layout 不會重新掛載。 |
loading.tsx |
該路由資料還沒抓完時顯示的載入畫面,內部用 React Suspense 實作。 |
error.tsx |
該路由發生錯誤時顯示的畫面,必須標記 "use client"。 |
not-found.tsx |
呼叫 notFound() 或找不到頁面時顯示的畫面。 |
巢狀 Layout
Layout 會依資料夾層級疊加。例如:
app/layout.tsx
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="zh-Hant">
<body>{children}</body>
</html>
);
}
app/blog/layout.tsx
export default function BlogLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<div className="blog-layout">
<aside>部落格側欄</aside>
<main>{children}</main>
</div>
);
}
造訪 /blog/hello-world 時,畫面會是 RootLayout 包住 BlogLayout、再包住 blog/[slug]/page.tsx 的內容。根 Layout 必須包含 <html> 與 <body>,且每個 Next.js 專案只能有一個根 Layout。
Route Groups(路由群組)
在資料夾名稱加上括號,例如 (marketing),可以把路由分類、共用 Layout,但不會出現在網址裡:
app/
├── (marketing)/
│ ├── layout.tsx # 行銷頁共用外框
│ ├── page.tsx # /
│ └── about/page.tsx # /about
└── (shop)/
├── layout.tsx # 商店頁共用外框
└── products/page.tsx # /products
這在同一個網站有多種頁面風格(例如行銷首頁 vs. 後台)時特別實用,可以各自套用不同 Layout 而不互相干擾。
下一步
固定路徑學會了,接著看網址中需要帶變數的情況,例如 /blog/[slug],詳見 動態路由。