Server Components
component ที่ไม่มีวันไปถึง browser
หัวข้อที่มีชื่อว่า “component ที่ไม่มีวันไปถึง browser”React Server Component (RSC) รันบน server, ผลิต output ที่นั่น และ ไม่ส่ง code ไปที่ client browser ได้รับแค่ ผลลัพธ์ ไม่ใช่ตัว component นั่นให้ประโยชน์สองอย่าง: dependency ของ component (Markdown parser, database client) ไม่ไปอยู่ใน client bundle และ component เข้าถึง resource ของ server ได้ตรง ๆ
เพราะรันบน server, Server Component จึงเป็น async และ fetch data แบบ inline ได้ — ไม่ต้อง useEffect, ไม่ต้องมี loading state, ไม่ต้อง round-trip ไป client:
// Server Component — runs on the server. Note: it's an async function.export default async function ProductPage({ id }) { const product = await db.products.findById(id); // direct DB access, on the server return ( <article> <h1>{product.name}</h1> <p>{product.description}</p> </article> );}ไม่มี 'use client' ตรงนี้ component นี้จึงเป็น Server Component: await data แล้ว return JSX; client เห็นแค่ markup ที่ render แล้วเท่านั้น
server/client boundary: 'use client'
หัวข้อที่มีชื่อว่า “server/client boundary: 'use client'”Server Component ทำเรื่อง interactive ไม่ได้ — ไม่มี useState, ไม่มี onClick, ไม่มี browser API เพราะ code นั้นไม่เคยรันใน browser เมื่อคุณต้องการ interactivity คุณข้ามไปเป็น Client Component โดยใส่ directive 'use client' ที่ด้านบนของไฟล์:
'use client';import { useState } from 'react';
// Client Component — ships to the browser, can use state and events.export default function AddToCart({ productId }) { const [count, setCount] = useState(0); return <button onClick={() => setCount((c) => c + 1)}>In cart: {count}</button>;}'use client' มาร์ค boundary: ไฟล์นั้นและทุกอย่างที่ไฟล์นั้น import จะกลายเป็น client code Server Component สามารถ render Client Component ได้ (server page ใส่ปุ่ม interactive ได้) แต่ทิศทางกลับกันไม่ได้แบบเดียวกัน — ทิศของ boundary สำคัญ
flowchart TB
subgraph server["Server (never shipped)"]
sc["Server Component
async, DB access, secrets"]
end
subgraph client["Client (shipped to browser)"]
cc["Client Component
use client, useState, onClick"]
end
sc -->|renders + passes
serializable props| cc อะไรข้าม boundary ได้บ้าง
หัวข้อที่มีชื่อว่า “อะไรข้าม boundary ได้บ้าง”Server Component ส่ง props ให้ Client Component แต่ props เหล่านั้นต้อง serializable — ต้องรอดจากการถูกส่งข้าม network ในรูปของ data:
- ✅ string, number, boolean, plain object/array, JSX และ promise (client resolve ด้วย
use()) - ❌ function (event handler), class instance หรืออะไรที่ถือ live state — serialize แล้วส่งไม่ได้
// Server Component passes a promise across the boundary:export default function Page() { const commentsPromise = fetchComments(); // not awaited here return <Comments commentsPromise={commentsPromise} />; // Client resolves it with use()}RSC มาจาก framework
หัวข้อที่มีชื่อว่า “RSC มาจาก framework”ข้อควรรู้ตามจริง: คุณไม่ได้ Server Components จาก react เปล่า ๆ + bundler RSC ต้องใช้ framework หรือ build setup ที่เข้าใจการแยก server/client และ serialize boundary ได้ — ในทางปฏิบัติคือ Next.js (App Router) และ framework อื่นที่รองรับ RSC แนวคิดเป็นของ React ส่วนการ wiring เป็นของ framework