Files
2nd/10_Wiki/Topics/Frontend/Composition API.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

187 lines
4.9 KiB
Markdown
Raw 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-composition-api
title: Composition API (Vue 3)
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Vue Composition API, setup script]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [vue, composition-api, reactivity, frontend]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: TypeScript
framework: Vue 3
---
# Composition API (Vue 3)
## 매 한 줄
> **"매 reactive primitive 으로 logic 을 조합한다"**. Composition API 는 Vue 3 의 `setup()` / `<script setup>` 기반 model — `ref`, `reactive`, `computed`, `watch` 를 직접 import 하여 매 logic 조각을 자유 조합, 매 Options API 의 `data/methods/computed` partition 을 대체.
## 매 핵심
### 매 핵심 primitives
- `ref(v)`: 매 wraps any value, `.value` access.
- `reactive(obj)`: deep proxy — object/array 만.
- `computed(fn)`: derived ref, lazy + cached.
- `watch(src, cb)`: explicit deps + cb.
- `watchEffect(fn)`: auto-track, eager.
- `effectScope()`: manual lifecycle group.
### 매 vs Options API
| Aspect | Options | Composition |
|---|---|---|
| Logic reuse | mixins (collision-prone) | composables (clean) |
| TypeScript | OK | excellent |
| File length scaling | grows by category | grows by feature |
| Learning curve | gentle | steeper but worth it |
### 매 `<script setup>` perks
- Top-level await.
- Auto-expose for template.
- `defineProps`, `defineEmits`, `defineModel`, `defineExpose` macros.
- Compile-time optimizations (no `setup()` boilerplate).
## 💻 패턴
### Basic setup with ref + computed
```vue
<script setup lang="ts">
import { ref, computed } from 'vue';
const count = ref(0);
const double = computed(() => count.value * 2);
const inc = () => count.value++;
</script>
<template>
<button @click="inc">{{ count }} (×2 = {{ double }})</button>
</template>
```
### Typed props + emits + v-model
```vue
<script setup lang="ts">
const props = defineProps<{ initial?: number }>();
const emit = defineEmits<{ change: [value: number] }>();
const model = defineModel<string>({ default: '' });
</script>
<template>
<input v-model="model" />
</template>
```
### reactive with toRefs (avoid losing reactivity)
```ts
import { reactive, toRefs } from 'vue';
export function useUser() {
const state = reactive({ name: 'Ada', age: 36 });
return { ...toRefs(state) }; // 매 destructurable + reactive
}
```
### watch with explicit source
```ts
import { ref, watch } from 'vue';
const query = ref('');
watch(query, async (q, _old, onCleanup) => {
const ctrl = new AbortController();
onCleanup(() => ctrl.abort());
const r = await fetch(`/search?q=${q}`, { signal: ctrl.signal });
// ...
});
```
### watchEffect (auto-track)
```ts
import { ref, watchEffect } from 'vue';
const userId = ref(1);
watchEffect(async () => {
const r = await fetch(`/api/users/${userId.value}`);
user.value = await r.json();
});
```
### Provide / inject (typed)
```ts
// keys.ts
import type { InjectionKey, Ref } from 'vue';
export const ThemeKey: InjectionKey<Ref<'light' | 'dark'>> = Symbol('theme');
// Parent
import { provide, ref } from 'vue';
const theme = ref<'light' | 'dark'>('dark');
provide(ThemeKey, theme);
// Child
import { inject } from 'vue';
const theme = inject(ThemeKey)!;
```
### Async setup with Suspense
```vue
<!-- Parent -->
<Suspense>
<UserProfile :id="42" />
<template #fallback><Skeleton /></template>
</Suspense>
<!-- UserProfile.vue -->
<script setup lang="ts">
const props = defineProps<{ id: number }>();
const user = await (await fetch(`/users/${props.id}`)).json();
</script>
```
### Lifecycle hooks
```ts
import { onMounted, onUnmounted } from 'vue';
onMounted(() => console.log('mounted'));
onUnmounted(() => console.log('cleanup'));
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| New Vue 3 project | Composition + `<script setup>` |
| Migrating from Vue 2 | Options 유지 → 점진 conversion |
| Logic reuse needed | Composable function |
| Simple 1-off component | Either OK, prefer setup for TS |
**기본값**: `<script setup>` + Composition API. Options API 는 legacy maintenance only.
## 🔗 Graph
- 부모: [[Vue 3]]
- 변형: [[Options-API]] · [[Solid-Signals]]
- 응용: [[Composables]] · [[Pinia]] · [[Nuxt]]
- Adjacent: [[Component-Composition]] · [[TypeScript]]
## 🤖 LLM 활용
**언제**: Vue 3 component 작성, composable 추출, TS 강한 typing 필요.
**언제 X**: Vue 2.7 이전 — 매 backport limited.
## ❌ 안티패턴
- **Mixing reactive() destructure without toRefs**: loses reactivity silently.
- **Using `ref.value` in template**: 매 unwrap 자동, `.value` 의 X.
- **Excessive `watch`**: 매 computed 로 충분한 경우 매 prefer computed.
## 🧪 검증 / 중복
- Verified (vuejs.org official guide).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — Composition API primitives + setup patterns |