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

Next.js คืออะไร และ App Router

Next.js คือ React framework ที่จัดการ routing, rendering, การ fetch data, bundling และ optimization ให้คุณ — และโมเดลปัจจุบันของตัวเองคือ App Router รัน component บน server โดย default

React เปล่า ๆ ให้แค่โมเดล component เท่านั้น ไม่มี routing ไม่มี server ไม่มี build pipeline Next.js เข้ามาเติมช่องว่างตรงนี้ เป็นชั้นที่ตัดสินว่า URL หนึ่งจะ map ไปที่โค้ดไหน โค้ดนั้นรันที่ไหน และผลลัพธ์เดินทางไปถึง browser ยังไง

พูดให้ชัด framework นี้ให้สิ่งเหล่านี้ —

  • Routing — โฟลเดอร์ใต้ app/ กลายเป็น URL segment ไม่ต้องมีไฟล์ config route ให้ดูแล
  • Rendering — render บน server ได้ทั้ง static และ dynamic, stream HTML และ hydrate เฉพาะส่วนที่ต้องการ interactivity
  • การ fetch data — คุณ await data ตรง ๆ ในตัว component บน server ได้เลย ไม่ต้องวิ่งไป-กลับที่ client
  • Bundling — compile และ split โค้ดด้วย Turbopack แต่ละ route จึงส่งเฉพาะสิ่งที่ตัวเองต้องใช้
  • Optimization — image, font, script และ metadata มี component กับ API ที่ built-in มาให้หมด

route ก็คือไฟล์ที่ default-export React component ออกมาเท่านั้น —

app/page.tsx
export default function HomePage() {
return <h1>Hello from a Server Component</h1>;
}

Next.js มีระบบ routing สองแบบ App Router (โฟลเดอร์ app/) คือโมเดลปัจจุบันที่แนะนำ สร้างบน React Server Components ส่วน Pages Router (โฟลเดอร์ pages/) คือโมเดลเก่า ยังใช้งานได้และ support เต็มที่ แต่ feature ใหม่ ๆ ไม่ได้มาลงที่นี่

ความต่างเป็นเชิงโครงสร้าง ไม่ใช่แค่ผิวเผิน —

app/ pages/
layout.tsx _app.tsx
page.tsx index.tsx
blog/ blog/
page.tsx index.tsx

ใน App Router component เป็น Server Components โดย default และการ fetch data เกิดขึ้นในบรรทัดเดียวกับ async/await ส่วนใน Pages Router ทุก component เป็น Client Component และ data มาจากฟังก์ชันพิเศษอย่าง getServerSideProps คอร์สนี้เป็นแบบ App-Router-first — Pages Router จะโผล่มาเฉพาะตรงที่การ migrate app เดิมสำคัญ

คุณ scaffold โปรเจกต์ใหม่ด้วยคำสั่งเดียว —

Terminal window
npx create-next-app@latest my-app

recommended defaults จะเซ็ตให้คุณด้วย TypeScript, ESLint, Tailwind CSS, App Router และไฟล์ AGENTS.md ต้นไม้ที่ถูกสร้างขึ้นจะมี app/ เป็นศูนย์กลาง —

my-app/
app/
layout.tsx # root layout (required)
page.tsx # the "/" route
next.config.ts
package.json
tsconfig.json

จากจุดนี้ npm run dev จะสตาร์ท development server แล้วคุณก็กำลังมอง App Router app ที่รันจริงอยู่

request ที่เข้ามาที่ App Router route ผ่านหลาย stage มากกว่าแค่ “รันฟังก์ชัน แล้วคืน HTML” เรียงลำดับ — มันผ่าน proxy.ts (ถ้ามี), Next.js match ไปที่ route segment, Server Components ของคุณ render ออกมาเป็น RSC payload (โดย cache layer ของ framework ตัดสินว่าอะไร fresh อะไรใช้ของเดิม), ผลลัพธ์ stream ไป browser เป็น HTML, browser hydrate Client Components ข้างในนั้น และทุกการ navigate หลังจากโหลดครั้งแรกจะ fetch RSC payload เพิ่มแทนที่จะโหลดทั้งหน้าใหม่ การเรียก Server Action ก็คือ POST request ที่กลับเข้า pipeline เดียวกันนี้ แต่ละ stage ถูกสอนแยกในบทของตัวเองที่อื่นในคอร์สนี้ The Request Lifecycle เดินเรื่องทั้งหมดแบบ end-to-end พร้อม header และ payload จริงที่พิสูจน์จาก app ที่รันอยู่จริง

flowchart LR
  Req[Browser request] --> Router[App Router]
  Router --> RSC[Server Components render on server]
  RSC --> HTML[Streamed HTML]
  Router --> Bundle[Minimal client bundle]
  HTML --> Page[Interactive page]
  Bundle --> Page
request ไหลผ่าน App Router ยังไง

คิดว่า Next.js คือทุกอย่างที่ React จงใจไม่ทำให้ — มันคือชั้นที่ตัดสินว่าโค้ด component ของคุณรัน ที่ไหน (server กับ browser), รัน เมื่อไร (build time, request time หรือทั้งคู่), และผลลัพธ์เดินทางไปถึงผู้ใช้ ยังไง App Router ไม่ใช่ templating language ใหม่ที่แปะเข้ากับ React — มันคือคำตอบปัจจุบันของ Next.js สำหรับสามคำถามนั้น สร้างบน React Server Components แทนที่จะเป็น single-page app แบบ client-only

ได้อะไรประโยชน์ต้นทุน
App Router (Server Components เป็น default)fetch data บรรทัดเดียวกับ await, client JS น้อย, streamingmental model ใหม่ถ้าคุณเรียน React แบบ client-only มาก่อน
Pages Router (เก็บไว้เพื่อ migrate)โมเดล getServerSideProps/getStaticProps ที่คุ้นเคย, ecosystem เก่าใหญ่มากทุก component เป็น Client Component ทั้งหมด ไม่มี feature ใหม่มาลงที่นี่
recommended defaults ของ create-next-appเส้นทางที่เร็วที่สุดไปสู่โปรเจกต์ที่ config ถูกต้องถ้าจะ customize ทีหลัง ต้องเข้าใจว่า default เลือกอะไรให้คุณไว้
framework เป็นเจ้าของ routing/rendering/bundlingคุณเขียนโค้ด infrastructure น้อยลงมากต้องเรียน convention ของ framework ไม่ใช่แค่ API ของ React
  • “Next.js เป็นแค่ router ให้ React” routing เป็นแค่หนึ่งในห้าอย่างที่มันเป็นเจ้าของ — มันยังตัดสิน rendering strategy, ergonomics ของการ fetch data, bundling และ optimization ในตัวสำหรับ image/font/script/metadata ด้วย
  • “App Router กับ Pages Router เป็นสองวิธีเขียนของแบบเดียวกัน” ทั้งสองต่างกันเชิงโครงสร้าง — component ของ App Router เป็น Server Component โดย default และ fetch data ในบรรทัดเดียวกับ async/await; component ของ Pages Router เป็น Client Component ทั้งหมด ป้อนข้อมูลด้วยฟังก์ชันแยกต่างหากอย่าง getServerSideProps โค้ดย้ายข้ามกันแบบ 1:1 ไม่ได้
  • “ทุก request แค่รันฟังก์ชัน page ของฉันแล้วคืน HTML” request หนึ่งผ่าน proxy, route matching, RSC rendering กับ cache layer หลายชั้น, streaming และ (ตอน navigate ครั้งถัดไป) การ fetch RSC ฝั่ง client — ดูภาพเต็มที่ The Request Lifecycle

เวลาโค้ดที่ generate มาอ้างว่าเป็น “Next.js page” เช็คสิ่งเหล่านี้ก่อนเชื่อ —

  • มันอยู่ใต้ app/ และ default-export component หรือเปล่า — หรือใช้ API เฉพาะ Pages Router (getServerSideProps, getStaticProps, ไฟล์ pages/) ในโปรเจกต์ที่ควรเป็น App Router?
  • มันสมมติว่า component เป็น Client Component (ใช้ useState/useEffect โดยไม่มี "use client") ทั้งที่จริงมันเป็น Server Component โดย default หรือเปล่า?
  • มัน fetch data ผ่าน API call แยกจาก component ทั้งที่ async Server Component await มันตรง ๆ ได้เลยหรือเปล่า?
  • มันเป็นคำแนะนำยุคก่อน App Router หรือเปล่า — เช่นถือว่า pages/api เป็นทางเดียวที่จะสร้าง endpoint ทั้งที่ Route Handlers (app/**/route.ts) คือของเทียบเท่าฝั่ง App Router?

🐛 หา bug ในโค้ดนี้

app/dashboard/page.tsx
export async function getServerSideProps() {
const res = await fetch('https://api.example.com/stats')
return { props: { stats: await res.json() } }
}
export default function Dashboard({ stats }: { stats: { views: number } }) {
return <p>Views: {stats.views}</p>
}
เฉลย

getServerSideProps เป็น export เฉพาะ Pages Router — ในไฟล์ใต้ app/ มันไม่ทำอะไรเลย ใน App Router Dashboard เป็น Server Component โดย default อยู่แล้ว จึง await การ fetch ตรง ๆ ในตัวมันเองได้เลย ไม่ต้อง export ฟังก์ชันโหลด data แยก stats ตรงนี้จะเป็น undefined เพราะ Next.js ไม่เรียก getServerSideProps ให้ route ของ App Router เลย ทางแก้คือทำให้ Dashboard เป็น async แล้ว await fetch(...) ตรงในตัวมันเอง ตาม pattern ใน Server and Client Components

App Router ใช้ component ชนิดไหนเป็น default
โฟลเดอร์ไหนบอกว่าโปรเจกต์ใช้ App Router
ข้อไหนที่ Next.js ไม่ได้ให้มาในตัว
คอร์สนี้ปฏิบัติกับ Pages Router ยังไง
เกิดอะไรขึ้นกับ stats เมื่อไฟล์นี้ถูกวางไว้ใต้ app/
// app/dashboard/page.tsx
export async function getServerSideProps() {
  const res = await fetch('https://api.example.com/stats')
  return { props: { stats: await res.json() } }
}

export default function Dashboard({ stats }: { stats: { views: number } }) {
  return <p>Views: {stats.views}</p>
}
ข้อความไหนถูกต้องเกี่ยวกับ tree ทั้งสองแบบนี้
app/                    pages/
  layout.tsx              _app.tsx
  page.tsx                index.tsx