docs(10_Wiki): 위키 전체 재구성 — Topic_* 폴더를 4개 카테고리로 통합 + 대규모 중복 제거

Topic_Agent/Topic_Blog/Topics/Topics_Biz/Topics_Meeting/Topics_Rag의 마크다운 지식 문서를
Topic_General/Topic_Programming/Topic_Graphic/Topic_Business 4개 카테고리로 재분류.

- 중복 제거: frontmatter의 status:duplicate/merged + duplicate_of/redirect_to 필드로
  자기 자신을 중복으로 선언한 리다이렉트 stub 1032개 제거, 완전 동일 내용 파일 472개 제거,
  동일 파일명·다른 내용 충돌 시 더 큰(완전한) 버전만 유지(162개 제거) — 총 1639개 중복 제거.
- 분류: 폴더 단위로 명확한 항목(AI_and_ML/Coding/Architecture 등 → Programming,
  Comfyui/Visual_Effects → Graphic, Topics_Biz/Topics_Meeting/사업 등 → Business,
  Poetic_Blog_Writing/창의성/Game_Design 등 → General)은 폴더 우선순위로,
  나머지 혼재 폴더(Topic_Agent/Topic_Blog/Topics 루트/Thinking & Reasoning/Other/UI_UX_Assets)는
  title/tags 키워드 스코어링으로 파일 단위 분류(불명확한 경우 General로 폴백).
  원본 폴더명은 "From_*" 서브폴더로 보존해 추적 가능성 유지.
- 최종 배치: Programming 2784 / General 1608 / Graphic 285 / Business 249 = 4926개 문서.
- 에이전트 운영 상태(.astra/.agent/.obsidian/sessions/memory/_company/docs/lessons/_shared/src)는
  지식 콘텐츠가 아니므로 재분류 대상에서 제외하고 원위치 유지.
- Topics/Topic_email(상위 보호 폴더 Topic_email과 파일명 100% 중복) 삭제 — 보호 폴더 자체는 미변경.
- 완전히 비게 된 Topic_Agent/Topic_Blog/Topics_Biz/Topics_Rag 폴더 제거.
This commit is contained in:
Antigravity Agent
2026-07-05 00:33:48 +09:00
parent 1cfd3bbb56
commit 9148c358d0
6455 changed files with 1 additions and 86875 deletions
@@ -0,0 +1,186 @@
---
id: wiki-2026-0508-대규모-데이터-렌더링-및-가상화-최적화
title: 대규모 데이터 렌더링 및 가상화 최적화
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Virtualization, Windowing, Virtual List, 가상 스크롤]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [frontend, virtualization, performance, react, rendering]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: typescript
framework: react
---
# 대규모 데이터 렌더링 및 가상화 최적화
## 매 한 줄
> **"매 보이는 것만 그린다"**. 100k row를 한 번에 mount 하면 DOM이 죽는다. Windowing 으로 viewport 안 ~30개만 render → scroll 시 recycle. 2026 표준은 TanStack Virtual / react-virtuoso, content-visibility CSS, 그리고 React 19의 `<Activity>` (offscreen).
## 매 핵심
### 매 왜 가상화가 필수인가
- DOM node 1개 ≈ 1-5KB memory + layout/paint cost.
- 10k+ row mount → 수백 MB heap, scroll jank, INP > 500ms.
- React reconciliation도 O(n) — fiber tree가 거대해지면 commit이 느려진다.
### 매 windowing 전략
- **Fixed size**: row height 동일 → offset = index × height. 가장 빠름.
- **Variable size**: row 마다 다름 → measured cache + estimated. ResizeObserver 로 동적 측정.
- **Dynamic load**: scroll 끝 도달 시 fetch (infinite scroll) — virtualization 과 결합.
### 매 응용
1. Admin table 100k+ row.
2. Chat history (역방향 virtualization).
3. Image gallery / Pinterest grid.
4. Code editor (Monaco-style line virtualization).
## 💻 패턴
### TanStack Virtual (2026 표준)
```tsx
import { useVirtualizer } from '@tanstack/react-virtual';
function VirtualList({ items }: { items: Row[] }) {
const parentRef = useRef<HTMLDivElement>(null);
const virtualizer = useVirtualizer({
count: items.length,
getScrollElement: () => parentRef.current,
estimateSize: () => 48,
overscan: 5,
});
return (
<div ref={parentRef} className="h-[600px] overflow-auto">
<div style={{ height: virtualizer.getTotalSize(), position: 'relative' }}>
{virtualizer.getVirtualItems().map(v => (
<div
key={v.key}
data-index={v.index}
ref={virtualizer.measureElement}
style={{
position: 'absolute',
top: 0,
left: 0,
width: '100%',
transform: `translateY(${v.start}px)`,
}}
>
{items[v.index].name}
</div>
))}
</div>
</div>
);
}
```
### Variable height with measurement
```tsx
const virtualizer = useVirtualizer({
count: rows.length,
getScrollElement: () => parentRef.current,
estimateSize: () => 80, // 매 best guess
measureElement: el => el.getBoundingClientRect().height, // 매 actual measure
overscan: 8,
});
```
### CSS content-visibility (zero-JS virtualization)
```css
.row {
content-visibility: auto;
contain-intrinsic-size: 0 48px; /* 매 placeholder size */
}
```
브라우저가 viewport 밖 element를 자동으로 skip layout/paint. React 없이도 효과.
### Infinite scroll + virtualization
```tsx
const { data, fetchNextPage, hasNextPage } = useInfiniteQuery({
queryKey: ['rows'],
queryFn: ({ pageParam = 0 }) => fetchPage(pageParam),
getNextPageParam: last => last.nextCursor,
});
const allRows = data?.pages.flatMap(p => p.items) ?? [];
const virtualizer = useVirtualizer({ count: allRows.length, /* ... */ });
useEffect(() => {
const last = virtualizer.getVirtualItems().at(-1);
if (last && last.index >= allRows.length - 5 && hasNextPage) {
fetchNextPage();
}
}, [virtualizer.getVirtualItems()]);
```
### Grid virtualization (2D)
```tsx
const rowVirtualizer = useVirtualizer({ count: rows, /* ... */ });
const colVirtualizer = useVirtualizer({
horizontal: true,
count: cols,
getScrollElement: () => parentRef.current,
estimateSize: () => 120,
});
// 매 nested loop: rows × cols 의 visible cells only.
```
### React 19 `<Activity>` for tab-like UI
```tsx
<Activity mode={isActive ? 'visible' : 'hidden'}>
<ExpensiveTab /> {/* 매 hidden 시 unmount X, but no render cost */}
</Activity>
```
### Server-side pagination + cursor
```ts
// 매 절대 client 에 100k row 보내지 마라.
GET /api/rows?cursor=abc123&limit=50
{ items: [...], nextCursor: 'def456' }
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| < 100 rows | 매 plain map. Virtualization X. |
| 100-1000 rows, fixed height | content-visibility CSS. |
| 1000+ rows | TanStack Virtual / react-virtuoso. |
| Variable height | measure + estimateSize. |
| Infinite stream | virtualization + cursor pagination. |
| Tab/accordion | React 19 `<Activity>`. |
**기본값**: TanStack Virtual + React Query infinite + content-visibility 보조.
## 🔗 Graph
- 부모: [[Frontend Performance]] · [[Rendering]]
- 변형: [[Infinite Scroll]] · [[Pagination]]
- 응용: [[Code Editor]]
- Adjacent: [[React Query]] · [[ResizeObserver]]
## 🤖 LLM 활용
**언제**: row count > 500, scroll 성능 issue, INP regression.
**언제 X**: static page, 매 작은 list (< 100), SEO-critical content (crawler 가 못 봄).
## ❌ 안티패턴
- **Mount all then hide**: `display: none` 으로 숨겨도 DOM 비용은 낸다.
- **Key as index**: row reorder 시 reconciliation 깨짐 — stable id 사용.
- **Inline measure on every render**: ResizeObserver + cache 필수.
- **No overscan**: scroll 시 빈 영역 보임. overscan 5-10.
- **Animation on virtualized rows**: 매 recycle 시 animation 초기화 — layout id 따로 관리.
## 🧪 검증 / 중복
- Verified (TanStack Virtual docs, Chrome DevTools, web.dev/content-visibility).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — virtualization + content-visibility + Activity 통합 |