⚛️ บทที่ 3: Server Components vs Client Components

เรียนรู้ความแตกต่างและการใช้งาน Server Components และ Client Components ใน Next.js 15 + React 19
35 นาที
ปานกลาง
สำคัญมาก
วัตถุประสงค์การเรียนรู้

เข้าใจความแตกต่างระหว่าง Server Components และ Client Components

รู้ว่าเมื่อไหร่ควรใช้ Server Components หรือ Client Components

สามารถสร้างและใช้งาน Server Components พร้อม React 19

เข้าใจการทำงานของ hydration และ React 19 concurrent features

🤔 React Server Components คืออะไร?

React Server Components เป็นฟีเจอร์ใหม่ที่ให้เราสามารถเรนเดอร์ React components บนเซิร์ฟเวอร์ได้ โดยไม่ต้องส่ง JavaScript ไปยังเบราว์เซอร์ ทำให้แอปพลิเคชันเร็วขึ้นและมี bundle size ที่เล็กลง

Server Components

เรนเดอร์บนเซิร์ฟเวอร์ และส่งผลลัพธ์ที่เป็น HTML ไปยังเบราว์เซอร์

✅ ไม่มี JavaScript ส่งไป client

✅ เข้าถึงฐานข้อมูลได้โดยตรง

✅ SEO-friendly

❌ ไม่รองรับ interactivity

Client Components

เรนเดอร์บนเบราว์เซอร์ เหมือนกับ React components แบบปกติ

✅ รองรับ interactivity เต็มรูปแบบ

✅ ใช้ React hooks ได้

✅ เข้าถึง browser APIs ได้

❌ ส่ง JavaScript ไป client

📊 เปรียบเทียบรายละเอียด

คุณสมบัติServer ComponentsClient Components
ที่ทำงาน
เซิร์ฟเวอร์
เบราว์เซอร์
JavaScript Bundle
ไม่ส่งไปยัง client
ส่งไปยัง client
State Management
ไม่รองรับ
รองรับ (useState, useEffect)
Event Handlers
ไม่รองรับ
รองรับ (onClick, onChange)
Browser APIs
ไม่เข้าถึงได้
เข้าถึงได้ (localStorage, window)
Data Fetching
ใช้ async/await โดยตรง
ใช้ useEffect + fetch
SEO
ดีมาก (เรนเดอร์ที่เซิร์ฟเวอร์)
ต้องการ hydration
Performance
Bundle เล็ก, โหลดเร็ว
Bundle ใหญ่กว่า

🎯 เมื่อไหร่ควรใช้อันไหน?

🖥️ ใช้ Server Components เมื่อ:
การดึงข้อมูลจาก API (React 19)

ดึงข้อมูลจากฐานข้อมูลหรือ external API ด้วย async/await ใน React 19

ตัวอย่าง: รายการสินค้า, ข้อมูลผู้ใช้, บทความ พร้อม enhanced caching

การแสดงข้อมูลคงที่

แสดงข้อมูลที่ไม่ต้องการ interaction พร้อม Static Route Indicator

ตัวอย่าง: หน้า About, Footer, Header (จะมี static indicator ใน dev)

การประมวลผลข้อมูล

คำนวณหรือประมวลผลข้อมูลที่ซับซ้อนด้วย React 19 Server Components

ตัวอย่าง: การคำนวณราคา, สถิติ, รายงาน ด้วย async functions

การเข้าถึงฐานข้อมูล

เชื่อมต่อและดึงข้อมูลจากฐานข้อมูลด้วย enhanced caching

ตัวอย่าง: Prisma queries, MongoDB operations (ไม่ cache by default ใน Next.js 15)

Hydration และการแก้ปัญหา

🔄 กระบวนการ Hydration
1. Server Rendering

เซิร์ฟเวอร์สร้าง HTML จาก Server Components และส่งให้เบราว์เซอร์

2. HTML Display

เบราว์เซอร์แสดง HTML ทันที (ผู้ใช้เห็นเนื้อหาได้แล้ว แต่ยังกดไม่ได้)

3. JavaScript Loading

เบราว์เซอร์ดาวน์โหลดและรัน JavaScript สำหรับ Client Components

4. Hydration Complete

React เชื่อมต่อ event handlers และทำให้เว็บไซต์ interactive

⚠️ Hydration Errors ที่พบบ่อย

สาเหตุ: เนื้อหาที่เรนเดอร์บนเซิร์ฟเวอร์ไม่ตรงกับที่เรนเดอร์บน client

// ❌ ผิด - เวลาต่างกันระหว่าง server และ client
function CurrentTime() {
  return <div>เวลาปัจจุบัน: {new Date().toLocaleTimeString()}</div>
}

// ✅ ถูก - ใช้ useEffect
function CurrentTime() {
  const [time, setTime] = useState('')
  
  useEffect(() => {
    setTime(new Date().toLocaleTimeString())
  }, [])
  
  return <div>เวลาปัจจุบัน: {time || 'กำลังโหลด...'}</div>
}

// ❌ ผิด - window ไม่มีบน server
function WindowWidth() {
  return <div>หน้าจอกว้าง: {window.innerWidth}px</div>
}

// ✅ ถูก - ตรวจสอบก่อนใช้
function WindowWidth() {
  const [width, setWidth] = useState(0)
  
  useEffect(() => {
    setWidth(window.innerWidth)
    
    const handleResize = () => setWidth(window.innerWidth)
    window.addEventListener('resize', handleResize)
    
    return () => window.removeEventListener('resize', handleResize)
  }, [])
  
  return <div>หน้าจอกว้าง: {width || 'กำลังตรวจสอบ...'}px</div>
}

// ❌ ผิด - Math.random() ให้ค่าต่างกันระหว่าง server และ client
function RandomColor() {
  const color = `#${Math.floor(Math.random() * 16777215).toString(16)}`
  return <div style={{ color }}>สีสุ่ม</div>
}

// ✅ ถูก - สร้างค่าสุ่มหลัง hydration
function RandomColor() {
  const [color, setColor] = useState('#000000')
  
  useEffect(() => {
    const randomColor = `#${Math.floor(Math.random() * 16777215).toString(16)}`
    setColor(randomColor)
  }, [])
  
  return <div style={{ color }}>สีสุ่ม</div>
}
💡 Best Practices สำคัญ

ใช้ Server Components เป็น default และเปลี่ยนเป็น Client เมื่อจำเป็น

แยกไฟล์ Server และ Client Components เพื่อความชัดเจน

ใช้ dynamic imports สำหรับ Client Components ที่ไม่จำเป็นต้องโหลดทันที

หลีกเลี่ยงการใช้ browser APIs ใน Server Components

ใช้ Suspense boundaries สำหรับ loading states ที่ดีขึ้น

🎯 ยินดีด้วย! คุณเรียนจบบทที่ 3 แล้ว

ตอนนี้คุณเข้าใจความแตกต่างระหว่าง Server Components และ Client Components แล้ว! พร้อมสำหรับการเรียนรู้เรื่อง Data Fetching และ Caching ในบทถัดไป