Next.js App Router
適用於 Next.js 14+ 搭配 app/ 目錄與 TypeScript。
檔案慣例
app/layout.tsx— 必要的根佈局。必須包含<html>與<body>。app/page.tsx— 路由入口。預設為 React Server Component (RSC)。app/loading.tsx— 該分段(segment)的串流後備(streaming fallback)。app/error.tsx— 必須是客戶端元件(Client Component,加上'use client'),接收{ error, reset }。app/not-found.tsx— 404 頁面。app/route.ts— Route Handler (API)。匯出GET、POST等。- 動態路由:
app/blog/[slug]/page.tsx取得{ params: { slug: string } }。 - 路由群組:
app/(marketing)/about/page.tsx— 不影響 URL。 - 平行路由:
app/@modal/page.tsx+layout({ modal })。攔截路由:app/(.)photo/[id]/page.tsx。
規則
- 預設使用伺服器元件(Server Components)。僅在需要使用 hooks、事件或瀏覽器 API 時才加上
'use client'。保持客戶端邊界最小,將它們推到葉節點。 - 在 Next 15 中,
params與searchParams為非同步:await params。 - 若伺服器元件使用了僅限伺服器的功能,切勿將其直接匯入客戶端元件 — 改以
children/props傳遞。 - 使用
next/link進行導航,next/navigation(useRouter、usePathname)僅用於客戶端元件。在伺服器元件中使用next/navigation的redirect()/notFound()。 - 協同佈置:每個分段放置
page.tsx、loading.tsx、error.tsx。共用 UI 放在components/,除非是路由頁面,否則不要放在app/。
範例
// app/blog/[slug]/page.tsx — Next 15 非同步 params
type Props = { params: Promise<{ slug: string }> };
export default async function BlogPost({ params }: Props) {
const { slug } = await params;
const post = await getPost(slug);
if (!post) notFound();
return <article>{post.title}</article>;
}
export async function generateStaticParams() {
const slugs = await getAllSlugs();
return slugs.map((slug) => ({ slug }));
}
// app/error.tsx — 必須是客戶端元件
'use client';
export default function Error({ error, reset }: { error: Error; reset: () => void }) {
return (
<div>
<h2>發生錯誤</h2>
<button onClick={() => reset()}>重試</button>
</div>
);
}
// app/layout.tsx
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}
檢查清單
- 檔名與分段放置正確嗎?
- 客戶端指令(
'use client')僅在必要處使用? - 非同步分段有提供
loading.tsx/error.tsx? - 需要 SEO 的地方有使用
generateStaticParams+generateMetadata? - 沒有從
next/router(pages-router 的匯入)使用useRouter?