Files
2nd/10_Wiki/Topics/Frontend/Re-renders Optimization.md
T
Antigravity Agent f8b21af4be Wiki cleanup: error-doc removal, dedup merge, link normalization
10_Wiki/Topics 대규모 정리:
- 오류 캡처/미완성 stub 문서 227개 제거
- 교차폴더 중복 43클러스터 병합 (63파일 → redirect)
- 링크명 정규화: 깨진 링크 수정·redirect 직결·개념 매핑 ~2,400건
- 카테고리 MOC 6개 신규 생성
- Graph 섹션 미해결 related-keyword 링크 10,058건 제거

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 23:52:15 +09:00

5.8 KiB

id, title, category, status, canonical_id, aliases, duplicate_of, source_trust_level, confidence_score, verification_status, tags, raw_sources, last_reinforced, github_commit, tech_stack
id title category status canonical_id aliases duplicate_of source_trust_level confidence_score verification_status tags raw_sources last_reinforced github_commit tech_stack
wiki-2026-0508-re-renders-optimization Re-renders Optimization 10_Wiki/Topics verified self
React Re-render Optimization
Render Performance
none A 0.9 applied
frontend
react
performance
memoization
react-compiler
2026-05-10 pending
language framework
TypeScript React 19

Re-renders Optimization

매 한 줄

"매 React 의 component re-render 의 최소화". 2026 React 19+ 매 React Compiler (auto-memo) 의 default 로 manual useMemo/useCallback 의 의미 약화. 매 measure first, optimize where needed.

매 핵심

매 Re-render Trigger

  • State change (useState, useReducer).
  • Parent re-render → child re-render (default).
  • Context value change → 매 consumer 전체 re-render.
  • Hook 의 internal state.

매 Tool (2026)

  • React Compiler (default in React 19+): 매 auto-memoization, useMemo/useCallback 거의 불필요.
  • React DevTools Profiler: 매 flame graph 로 re-render cost.
  • why-did-you-render: 매 dev-time unnecessary re-render 감지.
  • React Scan: 매 visual highlight (real-time).

매 핵심 기법

  • Component 분할 (state collocation).
  • React.memo (props equality).
  • useMemo / useCallback (compiler 가 대부분 자동).
  • Context split (frequently-changing 분리).
  • Virtualization (TanStack Virtual, react-window).

매 응용

  1. Large list rendering: virtualization.
  2. Form with many fields: react-hook-form register (uncontrolled).
  3. Heavy chart: memo + Canvas/WebGL.

💻 패턴

React Compiler (default 2026)

// React 19 with Compiler — 매 manual memo 거의 불필요
function ExpensiveList({ items, filter }: Props) {
  const filtered = items.filter(i => i.name.includes(filter)); // auto-memoized
  return <ul>{filtered.map(i => <li key={i.id}>{i.name}</li>)}</ul>;
}

매 State Collocation

// Bad: state in App, but only Modal needs it
function App() {
  const [modalOpen, setModalOpen] = useState(false);
  return (
    <>
      <ExpensiveTree /> {/* re-renders on toggle */}
      <Modal open={modalOpen} />
    </>
  );
}

// Good: state in wrapper
function App() {
  return (
    <>
      <ExpensiveTree />
      <ModalWrapper />
    </>
  );
}
function ModalWrapper() {
  const [open, setOpen] = useState(false);
  return <Modal open={open} />;
}

React.memo + useMemo 의 props

const Child = React.memo(({ data }: { data: Item[] }) => {
  return <ul>{data.map(i => <li key={i.id}>{i.name}</li>)}</ul>;
});

function Parent({ items, query }: Props) {
  // Without compiler: useMemo necessary
  const filtered = useMemo(() => items.filter(i => i.name.includes(query)), [items, query]);
  return <Child data={filtered} />;
}

Context Split

// Bad: single context, every change re-renders all
const AppContext = createContext({ user: null, theme: 'light', cart: [] });

// Good: split by change frequency
const UserContext = createContext<User | null>(null);
const ThemeContext = createContext<Theme>('light');
const CartContext = createContext<Cart>([]);

useSyncExternalStore (selector 의 fine-grained)

import { useSyncExternalStore } from 'react';
import { create } from 'zustand';

const useStore = create<State>(() => ({ count: 0, name: 'a' }));

function CountDisplay() {
  // Only re-render on count change
  const count = useStore((s) => s.count);
  return <div>{count}</div>;
}

Virtualization (TanStack Virtual)

import { useVirtualizer } from '@tanstack/react-virtual';

function BigList({ items }: { items: Item[] }) {
  const parentRef = useRef<HTMLDivElement>(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(), position: 'relative' }}>
        {virtualizer.getVirtualItems().map(v => (
          <div key={v.key} style={{ position: 'absolute', top: v.start, height: v.size }}>
            {items[v.index].name}
          </div>
        ))}
      </div>
    </div>
  );
}

React Scan (dev only)

import { scan } from 'react-scan';
if (process.env.NODE_ENV === 'development') {
  scan({ enabled: true, log: true });
}

매 결정 기준

상황 Approach
React 19+ project React Compiler (자동)
Legacy React 18 manual memo + Profiler
Large list (1000+) Virtualization
Complex form react-hook-form (uncontrolled)
Frequently-changing global state Zustand/Jotai with selector
Cross-cutting state Context (split by frequency)

기본값: 매 React 19 Compiler enable → measure → optimize hot path only.

🔗 Graph

🤖 LLM 활용

언제: Profiler 매 100ms+ render time 의 component, dropped frame, slow input. 언제 X: 매 micro-optimization without measurement — 매 premature.

안티패턴

  • 모든 곳 useMemo: 매 dependency 비교 cost > recomputation cost (특히 primitive).
  • Inline object/array as Context value: 매 every render new reference → consumer re-render.
  • React.memo without checking props: 매 props 가 항상 다르면 memo 무효 + cost 추가.
  • Optimization without Profiler: guessing → wasted effort.

🧪 검증 / 중복

  • Verified (React 19 docs, React Compiler RC, TanStack Virtual 3).
  • 신뢰도 A.

🕓 Changelog

날짜 변경
2026-05-08 Phase 1
2026-05-10 Manual cleanup — React Compiler / React Scan modern stack