Composition vs Options API
Composition API는 "무엇을 하느냐(기능)"로 코드를 구성하고, Options API는 "무엇이냐(역할)"로 구성합니다.
면접에서 "Composition API를 왜 쓰나요?"라는 질문에 "새로 나왔으니까요"가 아니라, 로직 재사용성과 코드 응집도 관점에서 답할 수 있어야 합니다.
Options API — 전통적인 방식
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
// 상태
data() {
return {
count: 0,
name: '심정훈'
}
},
// 계산된 속성
computed: {
doubleCount(): number {
return this.count * 2
}
},
// 감시자
watch: {
count(newVal: number, oldVal: number) {
console.log(`${oldVal} → ${newVal}`)
}
},
// 생명주기 훅
mounted() {
console.log('마운트됨')
},
// 메서드
methods: {
increment() {
this.count++
},
reset() {
this.count = 0
}
}
})
</script>
<template>
<p>{{ count }} (x2: {{ doubleCount }})</p>
<button @click="increment">증가</button>
<button @click="reset">리셋</button>
</template>
Composition API — 함수 기반 방식
<script setup lang="ts">
import { ref, computed, watch, onMounted } from 'vue'
// 상태
const count = ref(0)
const name = ref('심정훈')
// 계산된 속성
const doubleCount = computed(() => count.value * 2)
// 감시자
watch(count, (newVal, oldVal) => {
console.log(`${oldVal} → ${newVal}`)
})
// 생명주기 훅
onMounted(() => {
console.log('마운트됨')
})
// 메서드
const increment = () => {
count.value++
}
const reset = () => {
count.value = 0
}
</script>
<template>
<p>{{ count }} (x2: {{ doubleCount }})</p>
<button @click="increment">증가</button>
<button @click="reset">리셋</button>
</template>
핵심 차이 비교
| 항목 | Options API | Composition API |
|---|---|---|
| 코드 구성 | 역할별 (data, methods, computed...) | 기능별 (관련 로직을 묶음) |
| 로직 재사용 | Mixins (문제가 많음) | Composables (깔끔) |
| TypeScript | 제한적 (this 타입 추론 어려움) | 네이티브 지원 |
| 학습 곡선 | 낮음 (직관적 구조) | 중간 (반응형 이해 필요) |
| 코드 크기 | 작은 컴포넌트에서 간결 | 큰 컴포넌트에서 유리 |
| Tree-shaking | 제한적 | 사용한 API만 번들에 포함 |
로직 재사용 — Mixins의 문제와 Composables
Mixins의 문제점 (Options API)
// counterMixin.ts
export const counterMixin = {
data() {
return { count: 0 }
},
methods: {
increment() {
this.count++
}
}
}
// 문제 1: 어디서 온 속성인지 불명확
// 문제 2: 이름 충돌 가능성
// 문제 3: 여러 Mixin 간 암묵적 의존성
Composables의 해결 (Composition API)
// useCounter.ts
import { ref } from 'vue'
export function useCounter(initialValue = 0) {
const count = ref(initialValue)
const increment = () => { count.value++ }
const decrement = () => { count.value-- }
const reset = () => { count.value = initialValue }
return { count, increment, decrement, reset }
}
<script setup lang="ts">
import { useCounter } from './useCounter'
// 출처가 명확하고, 이름 충돌 없음
const { count, increment, reset } = useCounter(10)
// 여러 인스턴스를 독립적으로 사용 가능
const { count: count2, increment: increment2 } = useCounter(0)
</script>
<template>
<p>카운터1: {{ count }}</p>
<p>카운터2: {{ count2 }}</p>
</template>
코드 구성의 차이 — 큰 컴포넌트에서의 차이
Options API는 컴포넌트가 커질수록 관련 로직이 여러 옵션에 흩어집니다.
Options API에서 "검색 기능" 코드가 흩어지는 모습:
data() {
searchQuery: '', ← 검색 관련
users: [], ← 사용자 관련
searchResults: [] ← 검색 관련
}
computed: {
filteredUsers() {}, ← 사용자 관련
hasResults() {} ← 검색 관련
}
watch: {
searchQuery() {} ← 검색 관련
}
methods: {
fetchUsers() {}, ← 사용자 관련
handleSearch() {}, ← 검색 관련
clearSearch() {} ← 검색 관련
}
Composition API에서는 관련 로직을 한곳에 모을 수 있습니다.
<script setup lang="ts">
// === 검색 기능 ===
const searchQuery = ref('')
const searchResults = ref([])
const hasResults = computed(() => searchResults.value.length > 0)
watch(searchQuery, (query) => { /* 검색 로직 */ })
const handleSearch = () => { /* ... */ }
const clearSearch = () => { /* ... */ }
// === 사용자 기능 ===
const users = ref([])
const filteredUsers = computed(() => { /* ... */ })
const fetchUsers = async () => { /* ... */ }
</script>
두 API 혼용 가능
Vue 3에서는 같은 프로젝트에서 두 API를 혼용할 수 있습니다.
<!-- Options API 컴포넌트에서 Composition API 사용 -->
<script lang="ts">
import { defineComponent, ref } from 'vue'
import { useCounter } from './useCounter'
export default defineComponent({
// setup()은 Options API 안에서 Composition API를 쓸 수 있는 진입점
setup() {
const { count, increment } = useCounter()
return { count, increment }
},
data() {
return {
name: '심정훈'
}
},
computed: {
greeting(): string {
// setup에서 반환한 값도 this로 접근 가능
return `안녕하세요, ${this.name}! 카운트: ${this.count}`
}
}
})
</script>
어떤 것을 선택해야 할까?
| 상황 | 추천 API |
|---|---|
| 새 프로젝트 | Composition API (script setup) |
| Vue 2에서 마이그레이션 | Options API 유지하며 점진적 전환 |
| 작은 컴포넌트 | 어느 것이든 |
| 큰 컴포넌트 / 로직 재사용 | Composition API |
| TypeScript 사용 | Composition API |
| 프로토타이핑 / 학습 | Options API (직관적) |
면접 팁
- "Composition API가 무조건 좋다"가 아니라, 프로젝트 규모와 팀 상황에 따라 선택 한다는 답이 좋습니다
- Mixins의 세 가지 문제(출처 불명확, 이름 충돌, 암묵적 의존성)를 설명하고, Composables가 이를 어떻게 해결하는지 대비해서 설명하면 깊이 있어 보입니다
- React의 Custom Hooks와 Vue의 Composables를 비교할 수 있으면 프레임워크 이해도를 보여줄 수 있습니다
요약
Options API는 역할별로 코드를 구성하여 직관적이고, Composition API는 기능별로 구성하여 로직 재사용과 TypeScript 지원이 뛰어납니다. 새 프로젝트에서는 Composition API(script setup)를 권장하지만, 프로젝트 상황에 맞는 선택이 가장 중요합니다.
댓글 로딩 중...