
Next.js: Server Components vs Client Components
September 23, 2025
Front-end
ถ้าทุกคน ได้ลองเล่น Next.js เวอร์ชันใหม่ ๆ (ตั้งแต่เวอร์ชัน 13+ ที่มี App Router) คงจะเคยได้ยินคำว่า "Server Components" และ "Client Components" กันมาบ้างใช่ไหมครับ ตอนแรกอาจจะฟังดูงง ๆ หน่อย ว่ามันต่างจาก React ที่เราเคยเขียนมายังไง วันนี้เราจะมาไขข้อสงสัยนี้กันแบบง่าย ๆ ครับ!
การเปลี่ยนแปลงครั้งใหญ่: Server Components คือค่าเริ่มต้น!
สิ่งที่ต้องเข้าใจเป็นอันดับแรกและสำคัญที่สุดคือ:
ใน Next.js App Router, ทุก Component จะเป็น Server Component โดยอัตโนมัติ เว้นแต่เราจะบอกว่า "เฮ้! ตัวนี้เป็น Client Component นะ"
นี่คือการเปลี่ยนวิธีคิดครั้งใหญ่เลย จากเดิมที่เราคุ้นเคยว่า React Component ทั้งหมดจะทำงานบนเบราว์เซอร์ของผู้ใช้ (Client-side)
1. Server Components (พระเอกของเรา 🦸)
Server Components คือ Component ที่ทำงานและ render ตัวเองจนเสร็จสิ้น บนฝั่ง Server เท่านั้น จากนั้นจะส่งผลลัพธ์เป็น HTML ที่พร้อมแสดงผลไปให้เบราว์เซอร์
ลองนึกภาพเหมือนเชฟทำอาหารที่ร้านครับ เชฟ (Server) ปรุงอาหาร (Component) จนเสร็จสมบูรณ์ แล้วค่อยยกไปเสิร์ฟให้ลูกค้า (Client) ลูกค้าแค่รอทานอย่างเดียว ไม่ต้องปรุงเอง
จุดเด่นของ Server Components:
- เข้าถึง Back-end ได้โดยตรง: สามารถ async/await เพื่อดึงข้อมูลจากฐานข้อมูล, เรียกใช้ API, หรืออ่านไฟล์ได้โดยตรงใน Component เลย! ไม่ต้องสร้าง API route แยกเหมือนเมื่อก่อน
- ปลอดภัย: โค้ดที่เกี่ยวกับข้อมูลสำคัญ เช่น API keys หรือ database credentials จะไม่ถูกส่งไปให้เบราว์เซอร์เห็นเลย เพราะมันทำงานจบที่ Server
- Performance ดีเยี่ยม: JavaScript ของ Server Component จะไม่ถูกส่งไปให้ผู้ใช้ ทำให้ขนาดไฟล์ JS ที่ต้องดาวน์โหลดเล็กลงมาก ส่งผลให้เว็บโหลดเร็วขึ้นอย่างเห็นได้ชัด
ข้อจำกัด:
- ไม่มี Interactive: ไม่สามารถใช้ Hooks ที่ต้องพึ่งพา State หรือ Events ได้ เช่น useState, useEffect และไม่สามารถใส่ Event Handler อย่าง onClick, onChange ได้เลย
app/page.jsx
// นี่คือ Server Component (เพราะไม่มี "use client")
async function getProducts() {
const res = await fetch('https://api.example.com/products');
const products = await res.json();
return products;
}
export default async function HomePage() {
const products = await getProducts(); // ดึงข้อมูลตรงนี้เลย!
return (
<div>
<h1>รายการสินค้า</h1>
<ul>
{products.map((product) => (
<li key={product.id}>{product.name}</li>
))}
</ul>
</div>
);
}
2. Client Components (ผู้ช่วยคนสำคัญ 🧑🔧)
Client Components คือ Component แบบ "ดั้งเดิม" ที่เราคุ้นเคยกันดี มันจะถูก render ล่วงหน้าบน Server ก่อน (SSR) แล้วค่อยถูกส่งไปให้เบราว์เซอร์พร้อมกับไฟล์ JavaScript เพื่อให้มันมีชีวิตชีวาและโต้ตอบกับผู้ใช้ได้ (กระบวนการนี้เรียกว่า Hydration)
เราจะประกาศว่า Component นี้เป็น Client Component ด้วยการใส่ "use client" ไว้ที่บรรทัดบนสุดของไฟล์ครับ
ใช้ Client Components เมื่อไหร่?
เมื่อเราต้องการความ Interactive!
- เมื่อต้องใช้ Hooks เช่น useState, useEffect, useContext, useReducer
- เมื่อต้องมี Event Listeners เช่น onClick, onChange, onSubmit
- เมื่อต้องการเข้าถึง Browser APIs เช่น window, localStorage
- เมื่อต้องใช้ Custom Hooks หรือไลบรารีที่ต้องพึ่งพาสิ่งเหล่านี้
components/CounterButton.jsx
"use client"; // บอก Next.js ว่านี่คือ Client Component!
import { useState } from "react";
export default function CounterButton() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>
คุณคลิกไปแล้ว {count} ครั้ง
</button>
);
}
แล้วจะใช้ทั้ง Server Components และ Client Components ด้วยกันยังไงหล่ะ?
หัวใจสำคัญคือการผสมผสานทั้งสองแบบเข้าด้วยกันอย่างลงตัว โดยยึดหลักการนี้:
ให้ Component เป็น Server Component ไว้ให้มากที่สุด แล้วแยกส่วนที่ต้องการ Interactive ออกมาเป็น Client Component เล็ก ๆ
ลองดูตัวอย่างหน้าแสดงสินค้า ที่มีทั้งข้อมูลที่ดึงจาก Server และปุ่ม "เพิ่มลงตะกร้า" ที่ต้องเป็น Client Component
app/products/[id]/page.jsx
import AddToCartButton from "@/components/AddToCartButton";
// ฟังก์ชันดึงข้อมูลสินค้า (ทำงานบน Server)
async function getProductDetails(id) {
const res = await fetch(`https://api.example.com/products/${id}`);
return res.json();
}
// 1. page.jsx เป็น Server Component โดยปริยาย
export default async function ProductDetailPage({ params }) {
const product = await getProductDetails(params.id);
return (
<div>
<img src={product.image} alt={product.name} />
<h1>{product.name}</h1>
<p>{product.description}</p>
<p>ราคา: {product.price} บาท</p>
{/* 2. เรา import Client Component เข้ามาใช้ใน Server Component */}
<AddToCartButton productId={product.id} />
</div>
);
}
components/AddToCartButton.jsx
"use client"; // 3. ปุ่มนี้ต้องมี State และ onClick เลยเป็น Client Component
import { useState } from "react";
export default function AddToCartButton({ productId }) {
const [isAdding, setIsAdding] = useState(false);
const handleAddToCart = async () => {
setIsAdding(true);
console.log(`กำลังเพิ่มสินค้า ${productId} ลงตะกร้า...`);
// ...โค้ดสำหรับเพิ่มสินค้าลงตะกร้า...
await new Promise(resolve => setTimeout(resolve, 1000));
setIsAdding(false);
};
return (
<button onClick={handleAddToCart} disabled={isAdding}>
{isAdding ? "กำลังเพิ่ม..." : "เพิ่มลงตะกร้า"}
</button>
);
}
จากตัวอย่าง จะเห็นว่าเราให้หน้าหลัก (ProductDetailPage) เป็น Server Component เพื่อดึงข้อมูลและแสดงผลแบบนิ่ง ๆ ส่วนปุ่ม AddToCartButton ที่ต้องการ State และ onClick เราก็แยกมันออกมาเป็น Client Component เล็ก ๆ ทำให้เราได้ประโยชน์ทั้งสองฝั่ง ทั้ง Performance ที่ดีจาก Server และ Interactivity จาก Client
สรุปเปรียบเทียบ
คุณสมบัติ | Server Component | Client Component |
---|---|---|
ทำงานที่ไหน | บน Server เท่านั้น | Server (SSR) และ Client (Hydration) |
Interactive | ❌ ไม่ได้ | ✅ ได้ (ใช้ useState, useEffect, onClick) |
Data Fetching | ✅ ทำได้โดยตรง (async/await) | ⚠️ ทำได้ (แต่แนะนำใช้ useEffect หรือ SWR/TanStack Query) |
เข้าถึง Back-end | ✅ ได้ (DB, Filesystem) | ❌ ไม่ได้โดยตรง |
เข้าถึง Browser API | ❌ ไม่ได้ (window, localStorage) | ✅ ได้ |
Performance | ดีมาก (JS น้อย) | ขึ้นอยู่กับความซับซ้อน |
การเข้าใจความแตกต่างและวิธีใช้งานร่วมกันของ Server และ Client Components จะช่วยให้เราสร้างแอปพลิเคชัน Next.js ที่มีประสิทธิภาพสูงและทันสมัยได้ครับ หวังว่าบทความนี้จะช่วยให้ทุกคน เห็นภาพชัดเจนขึ้นนะครับ
Related Blogs
September 28, 2025
Next.js: สร้างเว็บเร็วฟ้าผ่า⚡ ด้วย SSG และ ISR🤔
เจาะลึก SSG และ ISR สองกลยุทธ์สร้างเว็บสุดเทพใน Next.js App Router ตั้งแต่เว็บนิ่งที่เร็วสุดขีด สู่เว็บที่อัปเดตตัวเองได้!

September 22, 2025
Zustand: State Management ที่ง่ายเหมือนปอกกล้วย
ปวดหัวกับ Prop Drilling? มาลอง Zustand ไลบรารีจัดการ State ที่เล็ก เบา และใช้ง่ายสุด ๆ กัน

September 21, 2025
เริ่มต้นกับ React Lifecycle
มารู้จัก React Lifecycle กันแบบเข้าใจง่าย ๆ เหมาะสำหรับคนเริ่มต้น
