🛑 1. The Performance Killer: "Re-rendering ทุกครั้งที่ติ๊กถูก"
ปัญหาใหญ่ของระบบ E-commerce คือเมื่อมีตัวกรอง (Filters) เยอะๆ ทุกครั้งที่ผู้ใช้คลิกเลือกสีหรือไซส์ แอปมักจะอาการค้างไปชั่วขณะ:
- สาเหตุ: การจัดการ State ที่ไม่ดีทำให้ทุก Card สินค้าต้องโหลดใหม่ (Re-render) ทั้งที่ควรจะเปลี่ยนแค่ตัวเลขผลลัพธ์เท่านั้น
Senior Solution: เราต้องใช้หลักการ "Optimistic UI" ผสมกับ "URL-State Management" เพื่อให้ระบบทำงานได้รวดเร็วที่สุดครับ
💡 2. Real-Life Analogy: พนักงานเสิร์ฟที่ต้องเดินกลับไปถามเชฟทุกคำถาม
- การกรองแบบแย่ (Standard State): ทุกครั้งที่คุณถามว่า "มีเมนูมังสวิรัติไหม" พนักงานต้องเดินกลับไปถามเชฟในครัว (API Call) แล้วคุณก็นั่งรอหน้าจืด
- การกรองแบบ Senior (Dual Layer Filtering): พนักงานมีเมนูอยู่ในมือแล้ว (Local Cache/URL State) เขาสามารถบอกคุณได้ทันทีว่ามีอะไรบ้าง ในขณะที่เขาส่งสัญญาณบอกเชฟให้เตรียมอาหารไว้รอ (Prefetching)
- บทสรุป: ผู้ใช้จะไม่รู้สึกถึงการรอ เพราะ UI ตอบสนองได้ทันที (Instant Feedback) ครับ
🚀 3. Execution Journey: ขั้นตอนการสร้าง Filter ระดับโปร (Impressa Style)
ในโปรเจกต์ Impressa Shop ผมใช้เทคนิคดังนี้เพื่อให้ UI ลื่นไหลที่สุด:
🛠 Step-by-step:
- URL as Single Source of Truth: เก็บค่า Filter ทั้งหมดไว้ใน Query Parameters (เช่น
?color=red&size=xl) เพื่อให้ผู้ใช้กด Back/Forward หรือส่ง Link ให้เพื่อนได้โดยที่ Filter ไม่หาย - Debouncing & Throttling: เมื่อผู้ใช้พิมพ์ค้นหา เราจะไม่ยิง API ทุกตัวอักษร แต่จะรอให้เขาหยุดพิมพ์สัก 300ms ก่อนเริ่มค้นหาจริง
- Skeleton Screens: ในระหว่างที่ข้อมูลใหม่กำลังโหลด เราจะแสดง Layout เปล่าๆ (Skeletons) ที่มีขนาดเท่าเดิม เพื่อไม่ให้หน้าเว็บ "กระตุก" (Layout Shift) ซึ่งทำลายประสบการณ์การใช้งาน
- TanStack Query (Cache Layer): เมื่อผู้ใช้กดย้อนกลับไปใช้ Filter เดิม ข้อมูลจะถูกดึงจาก Cache ทันทีโดยไม่ต้องโหลดจาก Server ใหม่
// ✅ การใช้ useSearchParams ร่วมกับ Next.js เพื่อทำ URL-State Filtering
function ProductFilters() {
const searchParams = useSearchParams();
const router = useRouter();
const handleFilterChange = (key, value) => {
const params = new URLSearchParams(searchParams);
params.set(key, value);
router.push(`?${params.toString()}`, { scroll: false });
};
// ...
}
🪤 4. The Junior Trap: "useEffect มหาศาลเพื่อ Sync State"
จูเนียร์มักจะใช้ useEffect เพื่อรอดูว่า Filter ตัวไหนเปลี่ยนแล้วค่อยยิง API:
- ปัญหา: มันควบคุมยากและมักเกิด Infinite Loop ได้ง่ายมาก (Race Condition)
- ✅ การแก้ไข: จงทำให้ Filter เป็น Stateless ให้มากที่สุด โดยให้ค่าทุกอย่างไหลมาจาก URL เพียงที่เดียวครับ
⚖️ 5. The UX Matrix: เร็วอย่างเดียวไม่พอ ต้อง "รู้สึก" ว่าเร็วด้วย
| เทคนิค | ความซับซ้อน | ผลลัพธ์ที่ได้ (UX) |
|---|---|---|
| Standard Map() | ง่าย | 🐌 ช้าและกระตุกเมื่อข้อมูลเยอะ |
| Virtual List | ปานกลาง | 🚀 แสดงผลลื่นไหลแม้มีสินค้าหมื่นชิ้น |
| Next.js Suspense | ปานกลาง | ✨ ประสบการณ์โหลดที่ไม่น่าเบื่อ |
| Server Actions Filtering | สูง | 💎 เร็วที่สุดเพราะงานหนักทำที่ Server |
🎓 6. Senior Mindset Summary
การทำระบบ Filter คือบทพิสูจน์ฝีมือของ Frontend Developer ว่าใส่ใจเรื่อง Performance และ UX แค่ไหนครับ อย่าลืมว่าทุกมิลลิวินาทีที่ผู้ใช้ต้องรอ คือโอกาสที่เขาจะปิดหน้าเว็บหนีไปหาคู่แข่ง การเขียนโค้ดให้เร็วไม่ใช่แค่เรื่องของ Logic แต่คือการเข้าใจ User Behavior ครับ!