ข้ามไปยังเนื้อหา

File Conventions และ Special Files

ใน App Router โฟลเดอร์นิยาม route segment และชื่อไฟล์ที่จองไว้ชุดเล็ก ๆ ให้พฤติกรรมกับแต่ละโฟลเดอร์ — โฟลเดอร์จะเข้าถึงเป็น URL ได้ก็ต่อเมื่อมี page อยู่ข้างใน

โฟลเดอร์ใต้ app/ คือ URL segment แต่โฟลเดอร์เปล่า ๆ ไม่ทำอะไร สิ่งที่ทำถูกตัดสินโดยไฟล์ที่จองไว้ข้างใน ชื่อไฟล์แต่ละอันมีหน้าที่เดียว —

  • page.tsx — UI ของ route และเป็นตัวที่ทำให้ segment นั้น route ได้แบบ public
  • layout.tsx — wrapper ที่ใช้ร่วมกัน คงอยู่ข้ามการ navigate และ nest ซ้อนใน parent layout
  • loading.tsx — Suspense fallback ที่แสดงระหว่าง segment กำลัง stream เข้ามา
  • error.tsx — error boundary ของ segment และต้องเป็น Client Component
  • not-found.tsx — UI ที่ render เมื่อ notFound() ถูกเรียก
  • route.ts — Route Handler คือ API endpoint แทนที่จะเป็น page
  • template.tsx — คล้าย layout แต่ re-mount instance ใหม่ทุกครั้งที่ navigate
app/
layout.tsx # root layout — wraps everything
page.tsx # "/"
dashboard/
layout.tsx # wraps everything under /dashboard
loading.tsx # fallback while /dashboard loads
error.tsx # catches errors in /dashboard
page.tsx # "/dashboard"
api/
users/
route.ts # "/api/users" — a Route Handler, not a page

page รับ route param และ search param แล้ว return UI ของ segment —

app/blog/[slug]/page.tsx
export default async function BlogPost({
params,
}: {
params: Promise<{ slug: string }>;
}) {
const { slug } = await params;
return <article>Reading: {slug}</article>;
}

layout ครอบ segment และทุกอย่างที่อยู่ข้างใต้ และเก็บ state ไว้ข้ามการ navigate ระหว่าง sibling page ดังนั้น chrome ที่ใช้ร่วมกันอย่าง sidebar จึงไม่ remount —

app/dashboard/layout.tsx
export default function DashboardLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<section>
<nav>Dashboard nav</nav>
{children}
</section>
);
}

ทุก App Router app ต้องมี root layout หนึ่งอันที่ app/layout.tsx เป็น layout เดียวที่ render tag <html> และ <body> เพราะ Next.js ไม่ได้ปล่อย tag พวกนี้ให้คุณ —

app/layout.tsx
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}

มีสองกฎที่ตามมาจากทั้งหมดนี้ กฎแรก โฟลเดอร์ที่ไม่มี page.tsx (หรือ route.ts) จะ route ไม่ได้ — คุณ nest โฟลเดอร์เพื่อจัดระเบียบไฟล์ล้วน ๆ ได้ และจะไม่ตอบสนองต่อ URL เลย กฎที่สอง error.tsx ต้องขึ้นต้นด้วย "use client" เพราะ error boundary พึ่งพา React ฝั่ง client

flowchart LR
  Folder[dashboard folder] --> Layout[layout wraps and persists]
  Layout --> Loading[loading is the Suspense fallback]
  Layout --> Error[error catches failures]
  Layout --> Page[page is the routable UI]
  Page --> URL[/dashboard is reachable]
How special files map onto a route segment
ไฟล์ไหนทำให้ route segment เข้าถึงได้แบบ public ที่ URL
อะไรคือสิ่งพิเศษของ error.tsx
อะไรที่อยู่เฉพาะใน root layout เท่านั้น
โฟลเดอร์ที่ไม่มีทั้ง page.tsx และ route.ts คือ: