ถ้าจะขึ้นโปรเจกต์ใหม่ด้วย React และต้องการแบบ SPAs ควรเลือกใช้อะไรดี ระหว่างใช้ Framework เช่น Next.js และ Vite
.
เรามาดูอนาคตของ SPA (Single Page Application) กันก่อน SPA เป็นแอพที่โหลดหน้าเว็บครั้งเดียว จากนั้นค่อยเรนเดอร์ทุกอย่างบนฝั่ง client ในบทความนี้จะพูดถึงรูปแบบปัจจุบัน และแนวคิดใหม่ๆ ในการพัฒนาแอพ แบบ SPA ที่อาจเกิดขึ้นในอนาคตอันใกล้นี้ครับ
.
รูปแบบปัจจุบัน (Current patterns)
1. Fetch-on-render (การดึงข้อมูลพร้อมกับการเรนเดอร์)
เดิมที SPA ส่วนใหญ่จะดึงข้อมูลภายในคอมโพเนนต์ (component) ขณะ map tree React ลงบน page ทำให้เกิดกระบวนการดังนี้
– เบราว์เซอร์ร้องขอ HTML
– แสดงผล UI จาก HTML เริ่มต้น
– ดาวน์โหลดไฟล์ JS
– แปลงรหัส (parse) และรัน JS เพื่อเริ่มต้น React
– เริ่มเรนเดอร์ tree React
– ดึงข้อมูลภายในคอมโพเนนต์ (fetch-on-render)
– แสดงผล fallback ของ <Suspense> ระหว่างรอข้อมูล
– เมื่อดึงข้อมูลเสร็จ จึงอัปเดต UI เป็นเวอร์ชันจริง
รูปแบบนี้แม้จะใช้งานง่าย แต่ถ้าไม่ระวังอาจทำให้เกิด “waterfall” ของการดึงข้อมูล และเลื่อนการแสดงผล UI ออกไป
.
2. Render-as-you-fetch (การเรนเดอร์พร้อมกับการดึงข้อมูล)
แตกต่างจากเดิมตรงที่เราเริ่มรันฟังก์ชันดึงข้อมูล (route loaders) ก่อน ที่ React จะเริ่มเรนเดอร์คอมโพเนนต์ ทำให้ขั้นตอนเป็นดังนี้
– เบราว์เซอร์ร้องขอ HTML
– แสดงผล UI จาก HTML เริ่มต้น
– ดาวน์โหลดไฟล์ JS
– แปลงรหัสและรัน React
– เรียกใช้ route loaders เพื่อดึงข้อมูลล่วงหน้า
– แสดงผล fallback ของ <Suspense> ในทันทีที่กำลังรอข้อมูล
– เมื่อดึงข้อมูลเสร็จ จึงอัปเดต UI เป็นเวอร์ชันจริง
การดึงข้อมูลก่อนการเรนเดอร์ช่วยลดเวลาเตรียมข้อมูล และเรนเดอร์ UI จริงได้เร็วยิ่งขึ้น ปัจจุบันสามารถใช้งานได้กับ React Router v7 (จริงๆ มีมาตั้งแต่ 6.x) และ TanStack Router
.
React Server Components (RSC)
แม้ชื่อจะฟังดูเกี่ยวกับ “เซิร์ฟเวอร์” แต่จริงๆ แล้วเราสามารถสร้าง React Server Components ให้เป็นสแตติกได้ตั้งแต่ขั้นตอน build แล้วค่อยส่ง payload ที่พร้อมใช้งานไปกับ SPA แบบคลาสสิก แนวทางนี้ยังไม่เป็นที่แพร่หลาย เพราะเฟรมเวิร์กส่วนใหญ่เน้นการเรนเดอร์ RSC บนเซิร์ฟเวอร์โดยตรง แต่ไอเดียคือ
– แยกคอมโพเนนต์ที่ไม่ขึ้นกับ session หรือ interaction ใดๆ
– สร้างล่วงหน้า (pre-generate) ก่อน build แอป
– โหลดตามความต้องการเมื่อคอมโพเนนต์นั้นถูกเรียกใช้ใน SPA
หากเกิดขึ้นจริง จะช่วยลดเวลาการเรนเดอร์คอมโพเนนต์ที่เป็นคอนเทนต์สแตติกลงมาก
.
Concurrent Features
React 18 เปิดตัวฟีเจอร์ concurrent เช่น useTransition และ useDeferred หลายคนมองว่าเหมาะกับ “แอปขนาดใหญ่” แต่ความเป็นจริงเราไม่ได้พูดถึงจำนวนผู้ใช้ แต่เป็น “ขนาดของ UI” ทั้งจำนวนหน้า ปริมาณ interaction และข้อมูลที่ไหลผ่าน UI
JavaScript ทำงานบน main thread หากมีหลาย interaction พร้อมกัน จะไม่สามารถควบคุมความสำคัญของแต่ละงานได้
ฟีเจอร์ concurrent ช่วยตั้งค่า “ลำดับความสำคัญ” (priority) ให้การอัปเดตบางส่วนรอได้ก่อน หรือเร่งทำก่อน ตามต้องการ
ผลลัพธ์คือ อินเทอร์เฟซที่ลื่นไหล ไม่ตกเฟรม และประสบการณ์ผู้ใช้ดีขึ้น
สำคัญที่นักพัฒนา React ควรสื่อสารให้ทีมดีไซน์เข้าใจ เพื่อออกแบบ interaction ที่ใช้ concurrent features ได้อย่างถูกต้อง
.
Preload (การโหลดล่วงหน้า)
เมื่อผู้ใช้กดลิงก์ข้ามหน้า SPA เราสามารถใช้ component ของ router (เช่น <Link>) เพื่อผสานกับกลไก preload:
– โค้ดหลัก (main bundle) โหลดก่อนเสมอ
– หน้าอื่นๆ แยกเป็นไฟล์ JS แยก (code splitting / lazy loading)
– เมื่อ user hover หรือโฟกัส <Link>
– เริ่ม preload ไฟล์ JS ของหน้าใหม่ พร้อมรัน route loaders ล่วงหน้า
– เมื่อคลิกแล้ว โหลดน้อยลง และเรนเดอร์เร็วขึ้น
การ preload นี้ช่วยลดเวลารอ และสร้างประสบการณ์คล้าย native app มากขึ้น
.
สิ่งที่ React Labs กำลังพัฒนา
จากบล็อกโพสต์ของ React Labs มีนวัตกรรม 2 อย่างที่น่าสนใจ:
1. ViewTransition
– เป็นมาตรฐานเว็บใหม่ สำหรับทำ animation ในการเปลี่ยนหน้า (page transition)
– React จะเชื่อม API ของ ViewTransition เข้ากับโมเดล React โดยอัตโนมัติ ช่วยให้สร้าง transition ระหว่างหน้าได้ลื่นไหลยิ่งขึ้น
2. Activity
– แนวคิดคล้ายกับ <Offscreen> แต่ทรงพลังกว่า
– แยกขั้นตอน render (เรียกคอมโพเนนต์เพื่อรับ virtual DOM) กับ commit (อัปเดต UI จริง) ออกจากกัน
– ให้เราสามารถ “pre-render” คอมโพเนนต์บางตัวเก็บไว้ก่อน แล้วเมื่อถึงเวลา commit จึงนำ virtual DOM ที่เตรียมไว้มาใช้ทันที
– ช่วยประหยัดเวลาเรนเดอร์ในช่วงโฟกัสจริง และผสานกับการ preload routing ได้ดี
หากรวม ViewTransition + preload + Activity เข้าด้วยกัน เราอาจได้ประสบการณ์การเปลี่ยนหน้าแบบ native-like บน SPA ในอนาคตอันใกล้นี้
.
สรุป
ถึงแม้จะมีการพัฒนา Server Rendering และ RSC อย่างต่อเนื่อง แต่รูปแบบ SPA คลาสสิกยังคงมีบทบาทสำคัญ การผสมผสานเทคนิคต่างๆ เช่น render-as-you-fetch, concurrent features, preload และนวัตกรรมจาก React Labs จะยกระดับประสบการณ์ผู้ใช้ให้ลื่นไหลขึ้น และตรียมพร้อมทางสู่อีกขั้นของการพัฒนาเว็บในอนาคต
.
ส่วนถ้าถามผมว่า ณ ตอนนี้ ถ้าอยากพัฒนา SPA ผมแนะนำให้ไป Next.js หรือ framework ที่ถนัดได้เลย ไม่ต้องเริ่มจากศูนย์เป็น best practices มาแล้วระดับหนึ่ง แต่หากต้องการควบคุมทุกอย่างเองตั้งแต่ต้น ก็สามารถใช้ Vite ขึ้นโปรเจคได้เช่นเดียวกัน แต่ทีมก็ต้องเข้าใจ React และไลบรารีที่เกี่ยวข้องเป็นอย่างดี โดยเฉพาะงานด้าน routing และ data-fetching