Back to Blog
Tối ưu hiệu suất React: Từ cơ bản đến nâng cao
React

Tối ưu hiệu suất React: Từ cơ bản đến nâng cao

Hướng dẫn chi tiết về các kỹ thuật tối ưu hiệu suất trong React applications.

5 tháng 1, 2024
10 phút đọc

Tối ưu hiệu suất React: Từ cơ bản đến nâng cao

Hiệu suất là yếu tố quan trọng trong việc phát triển ứng dụng React. Hãy cùng tìm hiểu các kỹ thuật tối ưu từ cơ bản đến nâng cao.

React.memo và useMemo

React.memo cho Components

const ExpensiveComponent = React.memo(({ data, onUpdate }) => {
  const expensiveValue = useMemo(() => {
    return data.reduce((acc, item) => acc + item.value, 0);
  }, [data]);

  return (
    <div>
      <h3>Total: {expensiveValue}</h3>
      <button onClick={onUpdate}>Update</button>
    </div>
  );
});

useMemo cho expensive calculations

function ProductList({ products, searchTerm, sortBy }) {
  const filteredAndSortedProducts = useMemo(() => {
    const filtered = products.filter(product =>
      product.name.toLowerCase().includes(searchTerm.toLowerCase())
    );
    
    return filtered.sort((a, b) => {
      if (sortBy === 'price') return a.price - b.price;
      if (sortBy === 'name') return a.name.localeCompare(b.name);
      return 0;
    });
  }, [products, searchTerm, sortBy]);

  return (
    <div>
      {filteredAndSortedProducts.map(product => (
        <ProductCard key={product.id} product={product} />
      ))}
    </div>
  );
}

useCallback cho Event Handlers

function TodoList({ todos, onToggle, onDelete }) {
  const handleToggle = useCallback((id) => {
    onToggle(id);
  }, [onToggle]);

  const handleDelete = useCallback((id) => {
    onDelete(id);
  }, [onDelete]);

  return (
    <div>
      {todos.map(todo => (
        <TodoItem
          key={todo.id}
          todo={todo}
          onToggle={handleToggle}
          onDelete={handleDelete}
        />
      ))}
    </div>
  );
}

Code Splitting với React.lazy

Component-level splitting

const LazyDashboard = React.lazy(() => import('./Dashboard'));
const LazyProfile = React.lazy(() => import('./Profile'));
const LazySettings = React.lazy(() => import('./Settings'));

function App() {
  return (
    <Router>
      <Suspense fallback={<div>Loading...</div>}>
        <Routes>
          <Route path="/dashboard" element={<LazyDashboard />} />
          <Route path="/profile" element={<LazyProfile />} />
          <Route path="/settings" element={<LazySettings />} />
        </Routes>
      </Suspense>
    </Router>
  );
}

Dynamic imports với conditions

function AdminPanel() {
  const [showAdvanced, setShowAdvanced] = useState(false);
  const [AdvancedComponent, setAdvancedComponent] = useState(null);

  useEffect(() => {
    if (showAdvanced && !AdvancedComponent) {
      import('./AdvancedSettings').then(module => {
        setAdvancedComponent(() => module.default);
      });
    }
  }, [showAdvanced, AdvancedComponent]);

  return (
    <div>
      <button onClick={() => setShowAdvanced(!showAdvanced)}>
        Toggle Advanced Settings
      </button>
      {showAdvanced && AdvancedComponent && <AdvancedComponent />}
    </div>
  );
}

Virtual Scrolling

Cho danh sách lớn, sử dụng virtual scrolling:

import { FixedSizeList as List } from 'react-window';

function VirtualizedList({ items }) {
  const Row = ({ index, style }) => (
    <div style={style}>
      <div className="item">
        {items[index].name}
      </div>
    </div>
  );

  return (
    <List
      height={600}
      itemCount={items.length}
      itemSize={50}
      width="100%"
    >
      {Row}
    </List>
  );
}

Image Optimization

Lazy loading images

function LazyImage({ src, alt, className }) {
  const [isLoaded, setIsLoaded] = useState(false);
  const [isInView, setIsInView] = useState(false);
  const imgRef = useRef();

  useEffect(() => {
    const observer = new IntersectionObserver(
      ([entry]) => {
        if (entry.isIntersecting) {
          setIsInView(true);
          observer.disconnect();
        }
      },
      { threshold: 0.1 }
    );

    if (imgRef.current) {
      observer.observe(imgRef.current);
    }

    return () => observer.disconnect();
  }, []);

  return (
    <div ref={imgRef} className={className}>
      {isInView && (
        <img
          src={src}
          alt={alt}
          onLoad={() => setIsLoaded(true)}
          style={{
            opacity: isLoaded ? 1 : 0,
            transition: 'opacity 0.3s'
          }}
        />
      )}
    </div>
  );
}

State Management Optimization

Tách state để tránh unnecessary re-renders

// ❌ Tránh - một state object lớn
function App() {
  const [state, setState] = useState({
    user: null,
    posts: [],
    comments: [],
    ui: { loading: false, error: null }
  });
  // Mỗi khi update bất kỳ field nào, toàn bộ component re-render
}

// ✅ Tốt hơn - tách state
function App() {
  const [user, setUser] = useState(null);
  const [posts, setPosts] = useState([]);
  const [comments, setComments] = useState([]);
  const [ui, setUi] = useState({ loading: false, error: null });
  // Chỉ re-render khi state liên quan thay đổi
}

Bundle Analysis

Sử dụng webpack-bundle-analyzer để phân tích bundle:

npm install --save-dev webpack-bundle-analyzer
{
  "scripts": {
    "analyze": "npm run build && npx webpack-bundle-analyzer build/static/js/*.js"
  }
}

Performance Monitoring

Sử dụng React DevTools Profiler

import { Profiler } from 'react';

function onRenderCallback(id, phase, actualDuration) {
  console.log('Component:', id);
  console.log('Phase:', phase);
  console.log('Duration:', actualDuration);
}

function App() {
  return (
    <Profiler id="App" onRender={onRenderCallback}>
      <Header />
      <Main />
      <Footer />
    </Profiler>
  );
}

Kết luận

Tối ưu hiệu suất React đòi hỏi sự hiểu biết sâu về cách React hoạt động và áp dụng đúng kỹ thuật cho từng tình huống. Những kỹ thuật này sẽ giúp ứng dụng React của bạn chạy mượt mà và mang lại trải nghiệm tốt cho người dùng.

Nhớ rằng: Đo lường trước khi tối ưu. Sử dụng React DevTools và browser performance tools để xác định bottlenecks thực sự.


Tags: React, Performance, Optimization, JavaScript, Web Development

Tags:

React
Performance
Optimization
JavaScript
Web Development