← Về danh sách bài họcBài 22/25
⚡ Bài 22: Performance - Tối Ưu Hiệu Suất
🎯 Sau bài học này, bạn sẽ:
- Hiểu re-render và khi nào cần tối ưu
- Dùng React.memo, useMemo, useCallback đúng lúc
- Code splitting với React.lazy và Suspense
- Sử dụng React DevTools Profiler
1. Re-render Trong React
Component re-render khi: state thay đổi, props thay đổi, hoặc parent re-render. Re-render KHÔNG phải lúc nào cũng xấu — React rất nhanh!
📌 Quy tắc: Đo trước, tối ưu sau. Dùng React DevTools Profiler để tìm bottleneck thực sự. Premature optimization là gốc rễ mọi tội lỗi.
2. React.memo
import { memo, useState, useCallback } from 'react';
// Wrap component tốn kém
const ExpensiveList = memo(function ExpensiveList({ items, onSelect }) {
console.log('ExpensiveList rendered');
return (
<ul>
{items.map(item => (
<li key={item.id} onClick={() => onSelect(item.id)}>
{item.name}
</li>
))}
</ul>
);
});
// Custom comparison
const UserCard = memo(
function UserCard({ user }) { return <div>{user.name}</div>; },
(prevProps, nextProps) => prevProps.user.id === nextProps.user.id
);3. Code Splitting & Lazy Loading
import { lazy, Suspense } from 'react';
// Lazy load heavy components
const HeavyChart = lazy(() => import('./HeavyChart'));
const AdminPanel = lazy(() => import('./AdminPanel'));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/chart" element={<HeavyChart />} />
<Route path="/admin" element={<AdminPanel />} />
</Routes>
</Suspense>
);
}
// Prefetch on hover
const LazyComponent = lazy(() => import('./Heavy'));
function Link() {
const prefetch = () => import('./Heavy'); // Start loading
return <a onMouseEnter={prefetch}>Open</a>;
}4. Virtualization (Danh Sách Lớn)
npm install @tanstack/react-virtualimport { useVirtualizer } from '@tanstack/react-virtual';
function VirtualList({ items }) {
const parentRef = useRef(null);
const virtualizer = useVirtualizer({
count: items.length,
getScrollElement: () => parentRef.current,
estimateSize: () => 40,
});
return (
<div ref={parentRef} style={{ height: 400, overflow: 'auto' }}>
<div style={{ height: virtualizer.getTotalSize() }}>
{virtualizer.getVirtualItems().map(row => (
<div key={row.key} style={{
position: 'absolute', top: row.start, height: row.size, width: '100%'
}}>
{items[row.index].name}
</div>
))}
</div>
</div>
);
}💡 Khi nào virtualize? Khi render 1000+ items. Virtualization chỉ render items trong viewport (thường 20-50 items), tăng tốc đáng kể.
📝 Tóm Tắt
- Đo trước, tối ưu sau — dùng React DevTools Profiler
React.memo: skip re-render khi props không đổiReact.lazy + Suspense: code splitting, lazy loading- Virtualization: cho danh sách 1000+ items
useMemo/useCallback: tối ưu computations và callbacks