Dark mode
React Performance Best Practices
การปรับปรุงประสิทธิภาพ (Performance) ใน React ช่วยให้แอปพลิเคชันของคุณลื่นไหล ตอบสนองไว และประหยัดทรัพยากร
ทำไม Performance ถึงสำคัญ?
- ผู้ใช้คาดหวังว่า UI จะตอบสนองเร็ว
- แอปที่ช้า = ประสบการณ์ใช้งานแย่ (User Experience)
- ประหยัด resource ทั้งฝั่ง client และ server
วัดก่อนปรับ (Measure before Optimize)
- อย่า optimize โดยไม่รู้จุดอ่อน ใช้ DevTools, React Profiler, Lighthouse ตรวจสอบก่อน
- ดูเวลาตอบสนอง, จำนวน re-render, ขนาด bundle, FPS
เทคนิคปรับปรุง Performance ที่สำคัญ
1. ใช้ React.memo ให้ถูกจุด
- React.memo ช่วยป้องกันการ re-render ที่ไม่จำเป็นของ functional component
- ใช้กับ component ที่รับ props เหมือนเดิมบ่อย ๆ
ตัวอย่างที่ดี
tsx
const ExpensiveList = React.memo(function ExpensiveList({ items }) {
// ...render list
});
ตัวอย่างที่ไม่ควรทำ
tsx
function ExpensiveList({ items }) {
// ...render list
} // ❌ re-render ทุกครั้งที่ parent เปลี่ยน
2. useMemo & useCallback
- useMemo: คำนวณค่าที่แพงและใช้ซ้ำ
- useCallback: สร้างฟังก์ชันที่ไม่เปลี่ยน reference ถ้า dependency ไม่เปลี่ยน
ตัวอย่างที่ดี
tsx
const filtered = useMemo(() => items.filter(...), [items]);
const handleClick = useCallback(() => { ... }, [dep]);
ตัวอย่างที่ไม่ควรทำ
tsx
const filtered = items.filter(...); // ❌ คำนวณใหม่ทุก render
const handleClick = () => { ... }; // ❌ ฟังก์ชันใหม่ทุก render
3. จัดการ State ให้เหมาะสม
- State ที่เปลี่ยนบ่อยควรอยู่ใกล้ component ที่ใช้ (local state)
- อย่าโยน state ขึ้นสูงเกินจำเป็น (avoid unnecessary lifting)
- ใช้ global state เฉพาะกรณีที่จำเป็นจริง ๆ
ตัวอย่างที่ดี
tsx
function List() {
const [selected, setSelected] = useState(null); // local state
}
ตัวอย่างที่ไม่ควรทำ
tsx
// State อยู่ที่ parent สูงเกินไป ทำให้ลูก re-render ทั้งหมด
4. การแบ่ง Component (Splitting)
- แบ่ง UI ใหญ่ ๆ ออกเป็น component ย่อย ๆ
- ช่วยให้ re-render เฉพาะส่วนที่จำเป็น
ตัวอย่างที่ดี
tsx
<Page>
<Sidebar />
<MainContent />
</Page>;
5. Lazy Loading & Code Splitting
- ใช้ React.lazy, Suspense โหลด component เฉพาะที่จำเป็น
- ลดขนาด bundle หลัก โหลดเร็วขึ้น
ตัวอย่างที่ดี
tsx
const Chart = React.lazy(() => import("./Chart"));
<Suspense fallback={<Spinner />}>
<Chart />
</Suspense>;
6. Optimize List Rendering
- ใส่ key ที่ไม่ซ้ำกันใน list
- ถ้า list ใหญ่ ใช้ virtualization (เช่น react-window, react-virtualized)
ตัวอย่างที่ดี
tsx
{
items.map(item => <Item key={item.id} />);
}
ตัวอย่างที่ไม่ควรทำ
tsx
{
items.map((item, i) => <Item key={i} />);
} // ❌ key ซ้ำได้
7. Suspense & Concurrent Features (React 18+)
- ใช้ Suspense ช่วยจัดการ loading state
- ใช้ startTransition สำหรับงานที่ไม่เร่งด่วน
ตัวอย่าง
tsx
import { startTransition } from "react";
startTransition(() => {
setInputValue(newValue);
});
8. หลีกเลี่ยงการสร้าง object/array ใหม่ใน props
- ถ้า props เป็น object/array ที่สร้างใหม่ทุกครั้ง จะทำให้ลูก re-render ตลอด
ตัวอย่างที่ดี
tsx
const config = useMemo(() => ({ theme }), [theme]);
<MyComponent config={config} />;
ตัวอย่างที่ไม่ควรทำ
tsx
<MyComponent config={{ theme }} />; // ❌ object ใหม่ทุก render
Tools สำหรับตรวจสอบ Performance
- React DevTools (Profiler tab)
- Chrome DevTools
- Lighthouse
- why-did-you-render (library สำหรับ debug re-render)
Checklist สรุป
- [ ] วัด performance ก่อน optimize
- [ ] ใช้ React.memo, useMemo, useCallback อย่างเหมาะสม
- [ ] จัดการ state ให้เหมาะสม (local > global)
- [ ] แบ่ง component และใช้ lazy loading
- [ ] optimize การ render list
- [ ] ใช้ Suspense/Concurrent features ถ้าเหมาะสม
- [ ] ตรวจสอบด้วย DevTools/Profiler
การ optimize performance ใน React ไม่ใช่แค่เรื่องเทคนิค แต่คือ mindset ที่ต้องวัดก่อนปรับ และเลือกใช้เทคนิคที่เหมาะกับปัญหาจริง ๆ เท่านั้น