Files
koriweb d8a80f6272 chore(wiki): dangling 링크 canonical 정규화 (768파일/1200건)
이름만 다른(표기 변형) [[위키링크]]를 대상 문서의 canonical 제목으로 치환해
끊겼던 1,200개 링크를 연결. 제목/파일명 정규화 일치만 적용하고 별칭 매칭은
과병합 위험으로 제외(애매성 가드). 원본은 _link_reconcile_backup/ 에 백업.
도구: Datacollect/scripts/link_reconcile_apply.mjs

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 12:24:15 +09:00

275 lines
7.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
id: wiki-2026-0508-dom-vs-virtual-dom
title: DOM vs Virtual DOM
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [DOM, Virtual DOM, vDOM, reconciliation, diffing, React fiber, Solid signals, Svelte compile]
duplicate_of: none
source_trust_level: A
confidence_score: 0.93
verification_status: applied
tags: [frontend, dom, virtual-dom, react, fiber, solid, svelte, signals, fine-grained-reactivity]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: JavaScript / React / Solid / Svelte
framework: React / Solid / Svelte / Vue
---
# DOM vs Virtual DOM
## 매 한 줄
> **"매 DOM mutation 의 expensive — 매 abstraction 의 batch"**. React 의 Virtual DOM (2013). 매 modern: 매 fine-grained reactivity (Solid, Svelte, Vue 3) 의 vDOM 의 supersede 의 trend. 매 pure DOM (vanilla, htmx) 의 revival.
## 매 핵심
### Real DOM
- 매 browser 의 tree.
- 매 mutation 의 reflow / repaint 의 trigger.
- 매 manual update 의 error-prone.
### Virtual DOM (React)
- 매 lightweight JS object 의 in-memory.
- 매 declarative state.
- 매 diff + 매 reconciliation 의 minimal real DOM update.
### 매 React 의 algorithm
1. 매 새 Virtual DOM tree.
2. 매 diff vs 매 previous (heuristic O(n)).
3. 매 minimal real DOM mutation.
### 매 React 의 heuristic
- **Different type** → 매 entirely new tree.
- **`key` attribute** → 매 stable child identity.
- **Component type same + props different** → 매 update only changed.
### 매 modern alternative
#### Fine-grained reactivity (Solid, Svelte 5, Vue 3)
- 매 vDOM 의 X.
- 매 signal / effect 의 specific DOM 의 update.
- 매 faster + smaller bundle.
#### Compile-time (Svelte)
- 매 framework 의 compile away.
- 매 매 component 의 specific imperative code.
#### htmx / Pure HTML
- 매 server-side render + 매 partial swap.
- 매 매 minimum JS.
### 매 trade-off
| 측면 | Real DOM | Virtual DOM | Fine-grained |
|---|---|---|---|
| Direct manipulation | Manual | Abstracted | Abstracted |
| Update granularity | Per-mutation | Per-component | Per-signal |
| Memory | Low | Medium | Low |
| Bundle size | Tiny | 50KB+ (React) | <10KB (Solid) |
| Rendering speed | Variable | Good | Best |
| Mental model | Imperative | Declarative + render fn | Declarative + signals |
### 매 React Fiber (2017)
- 매 reconciliation 의 interruptible.
- 매 priority-based.
- 매 concurrent rendering.
- 매 React 18+ default.
### 매 modern React 18+ optimization
- **Concurrent rendering**: 매 interrupt.
- **Automatic batching**.
- **Suspense + streaming**.
- **`useTransition` / `useDeferredValue`**.
- **RSC** (Server Components).
### 매 응용
1. **Large dynamic UI**: React / Solid.
2. **Static + light interactivity**: htmx / Astro islands.
3. **Form-heavy**: Solid (fast).
4. **SEO-critical**: Next.js (SSR).
5. **Data viz**: D3 + minimal framework.
## 💻 패턴
### React (declarative)
```jsx
function Counter() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>
Count: {count}
</button>
);
}
// React 가 매 setCount 시 의 새 vDOM → diff → 매 button text 만 update.
```
### `key` for stable identity
```jsx
function List({ items }) {
return (
<ul>
{items.map(item => (
<li key={item.id}>{item.name}</li> // 매 key 의 stable identity
))}
</ul>
);
}
```
### `useMemo` / `React.memo`
```jsx
const ExpensiveItem = React.memo(({ item, onClick }) => (
<div onClick={onClick}>{item.name}</div>
));
function List({ items, onSelect }) {
// 매 stable callback for memoization
const handleSelect = useCallback((id) => onSelect(id), [onSelect]);
const sorted = useMemo(() =>
items.sort((a, b) => a.priority - b.priority), [items]);
return sorted.map(item =>
<ExpensiveItem key={item.id} item={item} onClick={handleSelect} />
);
}
```
### Solid (signals, no vDOM)
```jsx
import { createSignal } from 'solid-js';
function Counter() {
const [count, setCount] = createSignal(0);
return (
<button onClick={() => setCount(count() + 1)}>
Count: {count()}
</button>
);
}
// 매 specific text node 의 update — 매 component re-render X.
```
### Svelte (compile-time)
```svelte
<script>
let count = 0;
</script>
<button on:click={() => count++}>
Count: {count}
</button>
<!-- 매 compile 의 imperative code 의 generate -->
```
### Vue 3 (Proxy-based reactivity + vDOM)
```vue
<script setup>
import { ref } from 'vue';
const count = ref(0);
</script>
<template>
<button @click="count++">Count: {{ count }}</button>
</template>
```
### htmx (no JS framework)
```html
<button hx-post="/click" hx-target="#count" hx-swap="innerHTML">
Click me
</button>
<span id="count">0</span>
<!-- 매 server 가 매 HTML 의 return → 매 swap -->
```
### Direct DOM (vanilla)
```js
const button = document.querySelector('button');
let count = 0;
button.addEventListener('click', () => {
count++;
button.textContent = `Count: ${count}`; // 매 direct mutation
});
```
### Concurrent rendering (React 18+)
```jsx
import { useTransition, useDeferredValue } from 'react';
function SearchableList({ items }) {
const [filter, setFilter] = useState('');
const deferred = useDeferredValue(filter);
const filtered = items.filter(i => i.name.includes(deferred));
return (
<>
<input value={filter} onChange={e => setFilter(e.target.value)} />
<List items={filtered} />
</>
);
}
```
### Performance comparison (React vs Solid)
```ts
// 매 typical bench:
// React useState + setCount: 매 10K updates → 매 500ms
// Solid signal + setCount: 매 10K updates → 매 50ms (10×)
```
### `<picture>` and DOM (no framework)
```html
<picture>
<source srcset="/img.avif" type="image/avif">
<img src="/img.jpg" alt="..." width="800" height="600">
</picture>
<!-- 매 HTML primitive 의 사용 -->
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| Large dynamic SPA | React + Concurrent |
| Performance-critical | Solid / Svelte |
| SEO + static + light JS | Astro + Islands |
| Form-heavy | Solid |
| Server-driven | htmx + HTML |
| Data viz | D3 + minimal |
| Vanilla / lib-free | Direct DOM |
**기본값**: React for ecosystem. Solid / Svelte for performance.
## 🔗 Graph
- 부모: [[Frontend]] · [[Web-Performance]] · [[React]]
- 변형: [[Virtual DOM]] · [[Fine-Grained-Reactivity]]
- 응용: [[React]] · [[Solid]] · [[Vue-3]] · [[htmx]] · [[Astro]]
- Adjacent: [[Critical_Rendering_Path]] · [[CSS Animations]] · [[Core Web Vitals Optimization (INP, LCP 개선)]] · [[Container_Queries]]
## 🤖 LLM 활용
**언제**: 매 framework selection. 매 perf optimization. 매 bundle size 의 reduce.
**언제 X**: 매 backend (다른 paradigm).
## ❌ 안티패턴
- **Direct DOM mutation in React**: 매 desync.
- **`key={index}` for dynamic list**: 매 wrong reconciliation.
- **No memoization (heavy re-render)**: 매 perf.
- **Premature memoization**: 매 over-engineering.
- **vDOM 의 large overhead** (small list): 매 vanilla 의 더 빠름.
## 🧪 검증 / 중복
- Verified (React docs, Solid docs, Svelte performance benchmark).
- 신뢰도 A.
- Related: [[Critical_Rendering_Path]] · [[CSS Animations]] · [[Core Web Vitals Optimization (INP, LCP 개선)]] · [[Container_Queries]] · [[Case-Study-Allbirds-PWA-Redesign]].
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — DOM vs vDOM vs fine-grained + 매 React / Solid / Svelte / htmx code |