코드도보통지

4관문. Expensive Computation

관문 4 / 7

무거운 정렬/필터 연산을 useMemo로 감싸 불필요한 재계산을 방지하라.

📖 이론 비급

useMemo: 계산 결과 메모이제이션

렌더마다 반복되는 무거운 연산은 useMemo로 감싸 의존성이 바뀔 때만 재실행한다.

판단 기준:

  • 연산 시간이 1ms 이상이면 메모이제이션 효과가 있다
  • React DevTools Profiler로 실제 렌더 시간을 측정하고 결정하라
  • 단순 계산에 useMemo를 남발하면 메모리와 코드 복잡도만 늘어난다

⚔️ 수련 코드

import { useState, useMemo } from 'react';

const DATA = Array.from({ length: 50000 }, (_, i) => ({
  id: i,
  name: `User ${i}`,
  score: Math.floor(Math.random() * 100),
}));

export default function SortedList() {
  const [query, setQuery] = useState('');
  const [sortDir, setSortDir] = useState('asc');
  const [theme, setTheme] = useState('light');

  // 문제: theme 변경 시에도 불필요한 정렬이 재실행된다
  const result = DATA
    .filter(d => d.name.includes(query))
    .sort((a, b) => sortDir === 'asc' ? a.score - b.score : b.score - a.score);
  // TODO: useMemo로 감싸라. 의존성: [query, sortDir]

  return (
    <div style={{ background: theme === 'dark' ? '#222' : '#fff' }}>
      <input value={query} onChange={e => setQuery(e.target.value)} placeholder="검색..." />
      <button onClick={() => setSortDir(d => d === 'asc' ? 'desc' : 'asc')}>정렬 전환</button>
      <button onClick={() => setTheme(t => t === 'light' ? 'dark' : 'light')}>테마 전환</button>
      <p>결과: {result.length}개</p>
    </div>
  );
}