← Về danh sách bài họcBài 22/25

⚡ Bài 22: Performance - Tối Ưu Hiệu Suất

⏱️ Thời gian đọc: 18 phút | 📚 Độ khó: Nâng cao

🎯 Sau bài học này, bạn sẽ:

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-virtual
import { 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