กลับไปที่บทความ
React Next.js Frontend Performance

React Server Components: รูปแบบเชิงปฏิบัติสำหรับผลิตภาพ

พลากร วรมงคล
20 กุมภาพันธ์ 2568 10 นาที

“Server Components เปลี่ยนแบบจำลองทางจิตใจของการพัฒนา React หลังจากสร้างแอป 2 แอปของผลิตภาพด้วย RSC นี่คือรูปแบบที่ใช้งาน ข้อผิดพลาดที่ต้องหลีกเลี่ยง และเมื่อ client components ยังคงเป็นทางเลือกที่ถูกต้อง”

การเปลี่ยนแปลงแบบจำลองทางจิตใจ

React Server Components (RSC) เปลี่ยนแปลงพื้นฐาน วิธีที่คุณคิดเกี่ยวกับสถาปัตยกรรม component แทนที่จะเป็น “ทุกอย่างทำงานในเบราว์เซอร์และเราดึงข้อมูลด้วย useEffect” ตอนนี้คุณมี components ที่ทำงานบนเซิร์ฟเวอร์ มี direct access กับฐานข้อมูลและ file system ของคุณ และส่งเพียง rendered HTML ไปยัง client

ความเข้าใจหลัก: Server Components เป็นค่าเริ่มต้น Client Components เป็นข้อยกเว้น นี่คือสิ่งตรงกันข้ามกับวิธีที่นักพัฒนา React ส่วนใหญ่สร้างแอปมาเป็นเวลาหลายปี และการเปลี่ยนแปลงทางจิตใจต้องใช้เวลา

เมื่อใดให้ใช้ Server vs Client Components

ต้นไม้การตัดสินใจนั้นเรียบง่ายกว่าบทความส่วนใหญ่:

ใช้ Server Components เมื่อ component ดึงข้อมูล เข้าถึง backend resources 렌เดอร์ static หรือ mostly-static content หรือไม่ต้องการ browser APIs หรือ interactivity นี่ครอบคลุมส่วนใหญ่ของ UI ของคุณ — layouts, pages, data displays, navigation structures

ใช้ Client Components เมื่อ component ต้องการ useState, useEffect หรือ hooks อื่น ๆ ตอบสนองต่อ user events (onClick, onChange) ใช้ browser-only APIs (localStorage, window, IntersectionObserver) หรือต้องการ real-time updates

ขอบเขตระหว่าง server และ client ชัดเจน: คุณเพิ่ม “use client” ที่ด้านบนของไฟล์ ทุกอย่างที่นำเข้าไปยัง client component จะกลายเป็นส่วนหนึ่งของ client bundle ดังนั้นให้จงใจเกี่ยวกับที่ที่คุณดึงเส้นนี้

รูปแบบ 1: ดึงข้อมูลที่ระดับหน้า

รูปแบบ RSC ที่ง่ายที่สุดและมีประสิทธิภาพสูงสุดคือดึงข้อมูลโดยตรงใน page component ของคุณ ไม่มี API routes ไม่มี useEffect ไม่มี loading states ที่ต้องจัดการ page component ของคุณเป็นฟังก์ชัน async ที่ await ข้อมูลและ render มัน

รูปแบบนี้ขจัด request waterfall ที่ระบาด React apps ดั้งเดิม ใน classic SPA เบราว์เซอร์จะดาวน์โหลด JavaScript เรียบเรียงมัน render component ยิง useEffect ทำ API call รอการตอบสนอง จากนั้น render ข้อมูล ด้วย RSC เซิร์ฟเวอร์จะดึงข้อมูล render HTML และส่ง complete result ไปยังเบราว์เซอร์ใน one round trip

รูปแบบ 2: การจัดองค์ประกอบ Server และ Client Components

รูปแบบการจัดองค์ประกอบเป็นรูปแบบที่สำคัญที่สุดในการโปรแกรม Server Components สามารถ render Client Components เป็น children แต่ Client Components ไม่สามารถนำเข้า Server Components โดยตรง

คุณสามารถ pass Server Components เป็น children หรือ props ให้กับ Client Components ตัวอย่างทั่วไป: Client Component ที่จัดการ dropdown หรือ modal state สามารถรับ content ของมันเป็น children prop ที่ render โดย Server Component

รูปแบบนี้ให้คุณเก็บ interactive shell ให้บาง (เพียงสภาวะ toggle และ animation) ในขณะที่เนื้อหาจริงจะ server-rendered และออกจาก JavaScript bundle ของคุณ

รูปแบบ 3: การ Streaming ด้วย Suspense

ขอบเขต Suspense ให้คุณ stream ส่วนต่างๆของหน้าของคุณอย่างอิสระ wrap slow data fetches ใน Suspense ด้วย fallback และ shell ของหน้าของคุณ render ทันทีในขณะที่ส่วนช้า stream เมื่อพวกเขาทำเสร็จ

ความเข้าใจหลักคือ granularity: wrap ส่วน data-dependent แต่ละส่วนใน Suspense ไม่ใช่ page ทั้งหมด dashboard อาจมี fast user profile section และ slow analytics section wrap ช่วง analytics section ใน Suspense หมายความว่า users เห็น profile ของพวกเขาทันทีในขณะที่ charts โหลด

นี่ดีกว่าการแสดง full-page spinner ขณะที่ query ช้าที่สุดของคุณเสร็จสิ้น

รูปแบบ 4: Server Actions สำหรับ Mutations

Server Actions แทนที่ API routes สำหรับการส่ง form และ mutations พวกเขาคือฟังก์ชันที่ทำเครื่องหมายด้วย “use server” ที่ทำงานบนเซิร์ฟเวอร์ แต่สามารถเรียก direct จาก client-side forms และ event handlers

รูปแบบทำงานตามธรรมชาติด้วย forms: prop action ของ form ของคุณชี้ไปยัง Server Action ซึ่ง receives FormData validates มัน writes ไปยัง database และ either returns result หรือ redirects ไม่มี manual fetch calls ไม่มี serialization ไม่มี API route files

สำหรับสถานการณ์ที่ซับซ้อนมากขึ้น คุณสามารถเรียก Server Actions จาก event handlers ใน Client Components นี่มีประโยชน์สำหรับ optimistic updates — update UI ทันที จากนั้นให้ Server Action persist change ในพื้นหลัง

รูปแบบ 5: การดึงข้อมูลแบบขนาน

เมื่อ Server Component ต้องการข้อมูลจากหลายแหล่ง ให้ดึงเขาแบบขนาน JavaScript’s Promise.all ให้คุณ fire multiple async operations พร้อมกันแทนที่จะเป็นลำดับ

ถ้าหน้าของคุณต้องการ user data ออเดอร์ของพวกเขา และการแจ้งเตือนของพวกเขา อย่า await พวกเขาทีละรายการ fire all three requests พร้อมกันและ await พวกเขาด้วยกัน นี่สามารถตัดเวลา page load ได้ 50-70% บนหน้าต่างๆที่มี multiple data dependencies

Pitfalls ทั่วไป

ใส่ “use client” สูงเกินไป

ข้อผิดพลาด performance ที่ใหญ่ที่สุดคือทำเครื่องหมาย component เป็น “use client” เมื่อเพียง small part ของมันต้อง interactivity นี่ pulls entire component และ imports ทั้งหมดเข้าไปในฝั่ง client bundle แทนที่จะเป็น extract interactive part เข้าไปในเล็ก Client Component และเก็บส่วนที่เหลือเป็น Server Component

ขอบเขต Serialization

ข้อมูลที่ผ่านจาก Server ไปยัง Client Components ต้อง serializable — ไม่มีฟังก์ชัน ไม่มี class instances ไม่มี Dates (พวกเขากลายเป็นสตริง) วางแผน component boundaries ของคุณด้วยการ serialization ในใจ ถ้าคุณต้องการ pass complex object พิจารณา restructuring มันเป็น plain JSON ก่อนข้ามขอบเขต

Over-Suspending

เพิ่ม Suspense boundaries มากเกินไปสร้างผล “popcorn” ที่ส่วนต่างๆของหน้าป๊อปอินในเวลาต่างๆ group related data fetches ภายใต้ single Suspense boundary สำหรับ user experience ที่นุ่มนวล goal คือ meaningful loading states ไม่ใช่หน้าที่ประกอบตัวเองชิ้นต่อชิ้น

พฤติกรรม Caching

Server Components มี cache อย่างก่ำเก็บ เข้าใจความแตกต่างระหว่าง static rendering (cached at build time) dynamic rendering (rendered per request) และ fetch cache ใช้ revalidate option เพื่อควบคุมว่านานเท่าใด cached data ยังคงสดใหม่ และ cache: ‘no-store’ option สำหรับข้อมูลที่ต้องเป็น live

Performance Wins

ในแอป production 2 แอป ที่ฉันสร้างด้วย RSC ผลลัพธ์คือ significant: JavaScript bundle size ลดลง 40-60% initial page load ปรับปรุงได้ 50% Time to First Byte ปรับปรุงเพราะ data fetching ย้ายไปเซิร์ฟเวอร์ (ใกล้กว่า database) และ Largest Contentful Paint ปรับปรุงอย่างมากเพราะ critical content renders ใน initial HTML

เมื่อ RSC ไม่ใช่คำตอบ

ไม่ใช่ทุก React app ที่ได้ประโยชน์จาก RSC ถ้าคุณกำลังสร้าง highly interactive application เช่น design tool real-time collaboration app หรือ game overhead ของ server rendering มีประโยชน์น้อย SPAs ที่มี heavy client-side state management (คิด Figma หรือ Google Docs) ยังคงมี better served โดย traditional client-side React

RSC ส่องแสงสำหรับ content-heavy applications dashboards e-commerce sites blogs และ CRUD apps — ซึ่ง to be fair อธิบาย majority ของ web applications สร้างในวันนี้

Comments powered by Giscus are not yet configured. Set PUBLIC_GISCUS_REPO_ID and PUBLIC_GISCUS_CATEGORY_ID in apps/web/.env to enable.

PV

เขียนโดย พลากร วรมงคล

Software Engineer Specialist ประสบการณ์กว่า 20 ปี เขียนเกี่ยวกับ Architecture, Performance และการสร้างระบบ Production

เพิ่มเติมเกี่ยวกับผม

บทความที่เกี่ยวข้อง