1. 라이프사이클 변경 개요
Vue 2 → Vue 3 마이그레이션에서 헷갈리기 쉬운 부분 중 하나가 라이프사이클 훅 이름과 인스턴스 API입니다.
공식 마이그레이션 가이드는 특히 아래 항목들을 브레이킹 체인지로 강조합니다.
- beforeDestroy와 destroyed → beforeUnmount와 unmounted로 이름 변경
- 일부 인스턴스 메서드 제거
- vm.$on, vm.$off, vm.$once
- vm.$children, vm.$listeners 등
오늘은 이 변경점들을 한 번에 정리하면서 기존 코드를 Vue 3 기준으로 어떻게 바꾸면 되는지를 보는 게 목표입니다.
2. 라이프사이클 훅 이름 매핑
- Options API 훅 이름 비교
Vue 2와 Vue 3에서 대부분의 훅 이름은 그대로지만, destroy 단계만 이름이 바뀌었습니다.
| Vue 2 | Vue 3 |
| beforeCreate | beforeCreate (동일) |
| created | created (동일) |
| beforeMount | beforeMount (동일) |
| mounted | mounted (동일) |
| beforeUpdate | beforeUpdate (동일) |
| updated | updated (동일) |
| beforeDestroy | beforeUnmount |
| destroyed | unmounted |
즉, 마이그레이션 관점에서는
- beforeDestroy → beforeUnmount
- destroyed → unmounted
이 두 개만 바꿔주면 됩니다.
// Vue 2
export default {
beforeDestroy() {
console.log('cleanup')
},
destroyed() {
console.log('destroyed')
}
}
// Vue 3
export default {
beforeUnmount() {
console.log('cleanup')
},
unmounted() {
console.log('destroyed')
}
}
- Composition API와의 대응
Vue 3에서 Composition API를 쓴다면 훅 이름은 onXXX 형태로 사용합니다.
import { onMounted, onUnmounted } from 'vue'
export default {
setup() {
onMounted(() => {
console.log('mounted')
})
onUnmounted(() => {
console.log('unmounted')
})
}
}
Options API와 맵핑하면 대략 이렇게 생각하면 편합니다.
| Options API | Composition API 훅 |
| mounted | onMounted |
| beforeUnmounted | onBeforeUnmount |
| unmounted | onUnmounted |
공식 가이드에서도 Vue 3에서는 Composition API 훅을 권장 방향으로 제시하고 있습니다.
3. 라이프사이클 이벤트 리스너 변경
Vue 2에서는 부모에서 자식의 라이프사이클 이벤트를 이런 식(@hook:)으로 들을 수 있었습니다.
<!-- Vue 2 -->
<MyChild @hook:mounted="onChildMounted" />
Vue 3에서는 이 prefix가 @vnode-로 바뀝니다.
<!-- Vue 3 -->
<MyChild @vnode-mounted="onChildMounted" />
destroy 훅도 마찬가지입니다.
<!-- Vue 2 -->
<MyChild @hook:beforeDestroy="onBeforeDestroy" />
<MyChild @hook:destroyed="onDestroyed" />
<!-- Vue 3 -->
<MyChild @vnode-beforeUnmount="onBeforeUnmount" />
<MyChild @@vnode-unmounted="onUnmounted" />
정리하면
- @hook: ... → @vnode-...
- 훅 이름 자체도 beforeDestroy, destroyed → beforeUnmount, unmounted로 변경
4. 인스턴스 이벤트 API 제거 ($on, $off, $once)
Vue 2의 이벤트 버스 패턴
Vue 2에서 자주 보이던 코드 패턴 중 하나가 컴포넌트 인스턴스를 이벤트 버스로 쓰는 것입니다.
// event-bus.js
import Vue from 'vue'
export const EventBus = new Vue()
// A.vue
EventBus.$on('notify', payload => { ... })
// B.vue
EventBus.$emit('notify', { message: 'hello' })
이때 쓰이던 인스턴스 메서드가 vm.$on, vm.$off, vm.$once입니다.
Vue 3에서는 제거
Vue 3에서는 이 인스턴스 이벤트 API들이 완전히 제거되었습니다.
- vm.$on
- vm.$off
- vm.$once
마이그레이션 가이드에서는 이 기능이 필요하면 외부 이벤트 라이브러리(예 - mitt, tiny-emitter)를 쓰라고 권장합니다.
예를 들어, mitt를 쓰면
// event-bus.js
import mitt from 'mitt'
export const emitter = mitt()
// A.vue
import { emitter } from '@/event-bus'
emitter.on('notify', (payload) => {
console.log(payload)
})
// B.vue
import { emitter } from '@/event-bus'
emitter.emit('notify', { message: 'hello' })
이제 Vue 인스턴스 자체를 이벤트 버스로 쓰지 말고,
별도의 작은 이벤트 라이브러리를 쓰자는 방향입니다.
5. $children, $listeners 제거와 대체 패턴
$children 제거
Vue 2에서는 부모 컴포넌트 안에서 직접 자식 인스턴스를 찾기 위해 this.$children을 쓰는 경우가 있었습니다.
// Vue 2
mounted() {
console.log(this.$children[0])
}
Vue 3에서는 $children이 제거되었습니다. 대신 ref + $refs 조합을 쓰는 것이 권장됩니다.
<!-- Vue 3 + Options API -->
<template>
<ChildComponent ref="child" />
</template>
<script>
export default {
mounted() {
console.log(this.$refs.child)
}
}
</script>
Composition API에서는 아래와 같습니다.
<!-- Vue 3 + Composition API -->
<script setup>
import { ref, onMounted } from 'vue'
import ChildComponent from './ChildComponent.vue'
const child = ref(null)
onMounted(() => {
console.log(child.value)
})
</script>
<template>
<ChildComponent ref="child" />
</template>
$listeners → $attrs 통합
Vue 2에서는 부모가 전달한 리스너를 자식에서 한번에 보려면 $listeners를 썼습니다.
// Vue 2
mounted() {
console.log(this.$listeners)
}
Vue 3에서는 $listeners와 $scopedSlots가 통합되어 $attrs로 제공됩니다.
// Vue 3
mounted() {
console.log(this.$attrs.onClick)
console.log(this.$attrs.onMouseenter)
}
- 이벤트 핸들러는 onXxx 형태의 attr로 전달됩니다.
- Composition API에서는 아래처럼 useAttrs()로 가져올 수 있습니다.
import { useAttrs, onMounted } from 'vue'
export default {
setup() {
const attrs = useAttrs()
onMounted(() => {
console.log(attrs.onClick)
})
return {}
}
}
6. 프로젝트에서 체크해야 할 코드
라이프사이클 훅
- beforeDestroy
- destoryed
- @hook: mounted, @hook: beforeDestroy, @hook: destroyed
→ Vue 3 기준으로 아래로 치환합니다.
- 훅 이름: beforeUnmount, unmounted
- 이벤트 리스너: @vnode-mounted, @vnode-beforeUnmount, @vnode-unmounted
인스턴스 이벤트 및 children/listeners
- this.$on(, this.$off(, this.$once(
- EventBus.$on, EventBus.$emit 패턴
- this.$children
- this.$listeners
→ 마이그레이션 전략
- 이벤트 버스
- 외부 라이브러리(mitt 등)로 대체
- $children
- ref / $refs 또는 명시적 props / emit 구조로 변경
- $listeners
- $attrs / useAttrs()로 접근
이 키워드들을 검색해보면 라이프사이클/인스턴스 API 관련해서
손봐야 할 양을 대략 파악할 수 있습니다.
정리
- 라이프사이클 이름 변경
- beforeDestory → beforeUnmount
- destoryed → unmounted
- Composition API에서는 onBeforeUnmount, onUnmounted 사용
- 라이프사이클 이벤트 리스너 변경
- @hook:mounted → @vnode-mounted
- @hoook:destroyed → @vnode-unmounted
- 인스턴스 이벤트 API 제거
- vm.$on, vm.$off, vm.$once 제거
- 필요하면 mitt, tiny-emitter 같은 외부 이벤트 라이브러리 사용
- $children / $listeners 제거
- $children → ref / $refs
- $listeners → $attrs / useAttrs()
- 실제 작업
- 위 키워드들로 코드 검색 → 영향 범위 파악
- 가장 단순한 컴포넌트부터 Options API 훅 이름과 이벤트 패턴을 Vue 3 스타일로 하나씩 바꿔보기
이 정도를 잘 정리해두면, 이후 주차에서 다루게 될 컴파일러 관련 변경(v-for, v-on keycode 등)이나
디렉티브/트랜지션 변경들을 이해할 때도 훨씬 수월해집니다.
출처
'Framework > Vue' 카테고리의 다른 글
| Vue 3 마이그레이션 연습용 샘플 Vue 2 프로젝트 준비하기 (0) | 2025.12.01 |
|---|---|
| Vue 2에서 Vue 3 마이그레이션 시 참고해야 할 체크리스트 (0) | 2025.12.01 |
| Vue 3에서 달라진 v-model과 템플릿 필터 제거 정리 (0) | 2025.11.28 |
| Vue 2의 Vue.use에서 Vue 3 Global API, createApp로 마이그레이션 (0) | 2025.11.27 |
| Vue 2에서 Vue 3로: 공식 마이그레이션 가이드 구조 한 눈에 정리 (0) | 2025.11.27 |