OPEN HYPER STEP
← 목록으로 (stack-analysis)
STACK-ANALYSIS · 99 / 120
stack-analysis
CHAPTER 99 / 120
읽기 약 2
FUNCTION

프론트엔드 렌더링 최적화: 가상화 + memo


핵심 개념

React.memo·useMemo·virtual list·windowing — 1만 항목도 60fps.

본문

React 리렌더 원리

TYPESCRIPT📋 코드 (17줄)
// 부모 리렌더 → 자식 모두 리렌더 (props 변화 무관)
function Parent() {
  const [count, setCount] = useState(0);
  return (
    <div>
      <button onClick={() => setCount(c => c + 1)}>+</button>
      <ExpensiveChild />  {/* 매번 리렌더 ❌ */}
    </div>
  );
}


// React.memo — props 변화 시만 리렌더
const ExpensiveChild = React.memo(() => {
  console.log('render');
  return <div>...</div>;
});

useMemo / useCallback

TYPESCRIPT📋 코드 (24줄)
function Component({ items }: { items: Item[] }) {
  // ❌ 매 렌더마다 새 객체
  const sorted = items.sort((a, b) => a.name.localeCompare(b.name));


  // ✅ items 변화 시만
  const sorted = useMemo(
    () => items.toSorted((a, b) => a.name.localeCompare(b.name)),
    [items]
  );


  // ❌ 매 렌더마다 새 함수 → 자식 memo 무효화
  const handleClick = (id: string) => doSomething(id);


  // ✅
  const handleClick = useCallback((id: string) => {
    doSomething(id);
  }, []);


  return <ChildList items={sorted} onClick={handleClick} />;
}

언제 memo? — 측정 우선

📋 코드 (12줄)
React.memo 비용:
- props 비교 (얕은 비교 자동)
- 효과 미미한데 코드 복잡도 증가

언제 쓸 것인가:
1. 큰 리스트의 항목 (1000+)
2. 비싼 렌더 (차트·계산)
3. 자주 리렌더되는 부모의 자식


React DevTools Profiler로 측정 후 결정
"premature optimization is the root of all evil"

가상화 (Virtual List)

TSX📋 코드 (44줄)
// 1만 항목 → DOM 1만 → 느림
import { useVirtualizer } from '@tanstack/react-virtual';

function LongList({ items }: { items: Item[] }) {
  const parentRef = useRef<HTMLDivElement>(null);

  const virtualizer = useVirtualizer({
    count: items.length,
    getScrollElement: () => parentRef.current,
    estimateSize: () => 50,
    overscan: 5,
  });

  return (
    <div ref={parentRef} style={{ height: 400, overflow: 'auto' }}>
      <div
        style={{
          height: virtualizer.getTotalSize(),
          position: 'relative',
        }}
      >
        {virtualizer.getVirtualItems().map(virtualRow => (
          <div
            key={virtualRow.index}
            style={{
              position: 'absolute',
              top: 0,
              left: 0,
              width: '100%',
              height: virtualRow.size,
              transform: `translateY(${virtualRow.start}px)`,
            }}
          >
            <ListItem item={items[virtualRow.index]} />
          </div>
        ))}
      </div>
    </div>
  );
}


// → DOM 10개만 (보이는 부분 + overscan)
// → 1만 항목도 60fps

React Compiler (자동 최적화)

TYPESCRIPT📋 코드 (16줄)
// React 19+ Compiler — 수동 memo 자동화
// .babelrc 또는 next.config.js
{
  "plugins": [
    "babel-plugin-react-compiler"
  ]
}


// 컴파일러가 자동 분석:
// - 어떤 값이 리렌더 시 변하는가
// - 자동으로 memoization 추가
// → 수동 useMemo/useCallback 불필요


// 단, 아직 베타 — 큰 프로젝트는 신중

key prop 정확히

TSX📋 코드 (11줄)
// ❌ index를 key로 — 순서 변경 시 깨짐
{items.map((item, i) => <Item key={i} {...item} />)}


// ✅ 안정적 ID
{items.map(item => <Item key={item.id} {...item} />)}


// 추가 항목, 정렬, 필터 시:
// ❌ index → 모든 항목 리렌더 + state 꼬임
// ✅ id → 변경된 항목만 리렌더

큰 객체 prop 분해

TYPESCRIPT📋 코드 (10줄)
// ❌ 큰 객체 통째로
<Component data={largeObject} />


// ✅ 필요한 것만
<Component name={largeObject.name} count={largeObject.count} />


// → memo 비교 빠름
// → 무관한 부분 변화 시 리렌더 X

React.lazy + Suspense

TSX📋 코드 (11줄)
import { lazy, Suspense } from 'react';

const HeavyChart = lazy(() => import('./HeavyChart'));

<Suspense fallback={<Skeleton />}>
  <HeavyChart />
</Suspense>


// 라우트 단위
const Dashboard = lazy(() => import('./pages/Dashboard'));

CSS — Avoid Reflow

CSS📋 코드 (16줄)
/* ❌ 매 프레임 layout 트리거 */
.element {
  transition: width 0.3s;
}


/* ✅ GPU 가속 (transform·opacity) */
.element {
  transition: transform 0.3s;
}


/* will-change — GPU 힌트 (남발 X) */
.animated {
  will-change: transform;
}

Profiler API

TSX📋 코드 (9줄)
import { Profiler } from 'react';

<Profiler id="App" onRender={(id, phase, actualDuration) => {
  if (actualDuration > 16) {  // 60fps = 16.67ms
    console.warn(`Slow render: ${id} ${phase} ${actualDuration}ms`);
  }
}}>
  <App />
</Profiler>

다음 챕터

CH.100 "성능 종합: Lighthouse 100점 달성 가이드".


AI 프롬프트
🤖 AI에게 잘 물어보는 법 — 모델·전략별 프롬프트
Claude

무료: Sonnet 4.6 / Pro $20/mo: Opus 4.6

내 코드의 React 렌더 최적화 부분을 분석해서
실전 분석 + 개선 우선순위를 알려줘.
ChatGPT

무료: GPT-5.5 / Plus $20/mo: GPT-5.5 Pro

React 렌더 최적화 관련 베스트 프랙티스 5가지를
비교 분석해서 패턴 추출를 알려줘.
Gemini

무료: 2.5 Flash / Pro $19.99/mo: 3.1 Pro

내 프로젝트 전체에서 React 렌더 최적화
최적화 가능 위치를 보고해줘.
Grok

무료: Grok 4.1 / SuperGrok $30/mo

2026년 한국 시장의 React 렌더 최적화
트렌드를 솔직히 알려줘.

⭐ 이것만 기억하세요
프론트엔드 렌더링 최적화: 가상화 + memo 이 3가지만 확실히 잡으세요
1.React.memo + useMemo + useCallback = 큰 리스트·비싼 컴포넌트만
2.가상화(@tanstack/react-virtual) = 1만+ 항목도 60fps
3.key는 안정적 ID — index는 순서 변경 시 깨짐


공유하기
진행도 99 / 120