Ⅰ. 이 글의 목표
이번 글의 목표는 저위험 컴포넌트부터 Vue 3 Composition API로 바꿔 보는 연습을 해보는 것입니다.
이미 Vue 3 + Compat build까지 해둔 상태라고 가정하고, 이번 글에서는
기존 Options API 컴포넌트 → Composition API <script setup>으로 변환하는 예시,
mixin / filter를 composable / 메서드로 치환하는 패턴을 샘플 코드 기준으로 정리해보려고 합니다.
Ⅱ. 변환 대상 컴포넌트 고르기
처음부터 로그인처럼 복잡한 컴포넌트보다는 비즈니스 로직이 거의 없고,
재사용되는 공통 UI이거나, 라우팅/스토어 의존성이 적은 단순 페이지를 먼저 고르는 게 좋습니다.
여기서는 Dashboard.vue를 예시로 사용해 보겠습니다.
기존 코드는 Vue2 Options API + Vuex 헬퍼를 쓰고 있습니다.
<!-- src/views/Dashboard.vue (변경 전) -->
<template>
<section class="dashboard">
<h2>Dashboard</h2>
<p v-if="user">환영합니다. {{ user.name }}님</p>
<p v-else>로그인 정보가 없습니다.</p>
<button @click="onLogout">로그아웃</button>
</section>
</template>
<script>
import { mapGetters, mapActions } from 'vue'
export default {
name: 'Dashboard',
computed: {
...mapGetters('auth', ['currentUser']),
user() {
return this.currentUser
}
},
methods: {
...mapActions('auth', ['logout']),
onLogout() {
this.logout()
this.$router.push({ name: 'login' })
}
}
}
</script>
Ⅲ. <script setup> + Composition API로 변환
Vue 3 환경(compat 포함)에서는 <script setup>이 가장 간결한 작성 방식입니다.
같은 컴포넌트를 <script setup> 기반 Composition API로 바꾸면 이렇게 됩니다.
<!-- src/views/Dashboard.vue (변경 후) -->
<template>
<section class="dashboard">
<h2>Dashboard</h2>
<p v-if="user">환영합니다. {{ user.name }}님</p>
<p v-else>로그인 정보가 없습니다.</p>
<button @click="onLogout">로그아웃</button>
</section>
</template>
<script setup>
import { computed } from 'vue'
import { useStore } from 'vuex'
import { useRouter } from 'vue-router'
const store = useStore()
const router = useRouter()
const user = computed(() => store.getters['auth/currentUser'])
const onLogout = () => {
store.dispatch('auth/logout')
router.push({ name: 'login' })
</script>
- export default { ... } → <script setup>으로 교체
- mapGetters 대신 useStore() + computed로 직접 getter 조회
- mapActions 대신 store.dispatch 직접 호출
- this.$router 대신 useRouter() 사용
처음에는 Vuex/Router 의존성이 전혀 없는 더 단순한 컴포넌트(공통 버튼, 카드 등)를
하나 골라 <script setup> 변환 연습을 먼저 해보는 것도 좋습니다.
Ⅳ. 간단한 mixin을 composable로 치환해 보기
실제 프로젝트에서는 mixin을 써서 공통 로직을 공유하는 경우가 많습니다.
예를 들어 날짜 포맷용 mixin이 있다고 가정해보겠습니다.
// src/mixins/dateMixin.js (변경 전 예시)
export default {
methods: {
$formatDate(date) {
if (!date) return ''
return new Intl.DateTimeFormat('ko-KR', {
year: 'numeric',
month: '2-digit',
day: '2-digit'
}).format(new Date(date))
}
}
}
이 mixin을 쓰는 컴포넌트 예시는 아래와 같습니다.
<template>
<p>가입일: {{ $formatDate(user.createdAt) }}</p>
</template>
<script>
import dateMixin from '@/mixins/dateMixin'
export default {
mixins: [dateMixin],
props: { user: Object }
}
</script>
Vue 3에서는 mixin보다 composable 함수를 권장합니다.
같은 기능을 composable로 옮겨보면 아래와 같습니다.
// src/composables/useDateFormat.js (변경 후)
export function useDateFormat {
const formatDate = (date) => {
if (!date) return ''
return new Intl.DateTimeFormat('ko-KR', {
year: 'numeric',
month: '2-digit',
day: '2-digit'
}).format(new Date(date))
}
return { formatDate }
}
컴포넌트에서는 이렇게 사용합니다.
<template>
<p>가입일: {{ formatDate(user.createdAt) }}</p>
</template>
<script setup>
import { useDateFormat } from '@/composables/useDateFormat'
const props = defineProps({
user: Object
})
const { formatDate } = useDateFormat()
</script>
어디서 어떤 기능을 가져왔는지 명시적(import)이고
타입/IDE 지원이 mixin보다 훨씬 좋으며
여러 composable을 조합하기도 편합니다.
Ⅴ. 템플릿 필터를 메서드/컴포저블로 치환
Vue 2에서 자주 보이던 템플릿 필터 예시를 하나 들어볼게요.
<!-- Vue 2 스타일 -->
<p>상태: {{ status | uppercase }}</p>
// 전역 필터
Vue.filter('upppercase', value => (value || '').toUpperCase())
Vue 3에서는 템플릿 필터 문법이 완전히 제거되므로 컴포넌트 메서드나 composable로 바꿔야 합니다.
가장 단순한 방법은 메서드로 치환하는 것입니다.
<!-- Vue 3 스타일 -->
<template>
<p>상태: {{ toUpper(status) }}</p>
</template>
<script setup>
const props = defineProps({
status: String
})
const toUpper = (value) => (value || '').toUpperCase()
</script>
혹은 아까처럼 useFormatter 같은 composable에 모아 둘 수도 있습니다.
Ⅵ. 실제 프로젝트에 적용할 때 팁
실제 코드에 적용할 때는 아래 순서를 추천합니다.
- 변경 범위가 작은 컴포넌트부터
- 공통 버튼, 카드, 단순 정적 페이지 등
- 외부 라이브러리 의존성이 없는 것부터 시도
- Options API와 Composition API를 섞어두는 기간을 허용
- compat 모드에서는 둘이 공존해도 됨
- 굳이 하루만에 전체를 바꾸려고 하지 말 것
- main/filter부터 서서히 줄여나가기
- mixin에 들어 있는 로직을 composable로 옮긴 뒤, 기존 컴포넌트를 하나씩 새 함수로 전환
- 템플릿 필터는 경고가 뜨기 쉬우니 우선순위를 높게 잡기
- 각 변환마다 전/후를 커밋으로 남기기
- 예) feat: migrate Dashboard to <script setup>
- 나중에 문제 생겼을 때 쉽게 비교 가능
정리
- 샘플 Vue 2 컴포넌트 하나를 골라 Composition API <script setup>로 변환
- mixin-filter 같은 레거시 패턴을 composable / 메서드로 치환하는 기본 패턴을 익힘
Compat Build 덕분에 아직은 Vue 2 스타일 코드와 섞여 있어도 돌아가므로,
당장은 전체 마이그레이션보다 작은 단위로 연습하는 데 집중하면 됩니다.
다음 글에서는 이 흐름을 상태 관리 쪽으로 확장해서,
Vuex 모듈 하나를 Pinia store로 옮기는 연습을 해볼 예정입니다.
출처
'Framework > Vue' 카테고리의 다른 글
| Vuex 모듈 하나를 Pinia로 옮겨보기 (0) | 2025.12.03 |
|---|---|
| Vue 3 Compat Build로 Vue 2 프로젝트 안전하게 버전업 (0) | 2025.12.01 |
| Vue 3 마이그레이션 연습용 샘플 Vue 2 프로젝트 준비하기 (0) | 2025.12.01 |
| Vue 2에서 Vue 3 마이그레이션 시 참고해야 할 체크리스트 (0) | 2025.12.01 |
| Vue 3 라이프사이클과 인스턴스 API 변경 정리 (0) | 2025.11.28 |