
Vue.js의 생명주기(lifecycle)는 컴포넌트의 생성, 업데이트, 파괴 등의 과정을 관리하는 데 중요한 역할을 합니다.
각 생명주기 단계에서 특정 훅(hook)을 사용하여 필요한 작업을 수행할 수 있습니다. 생명주기 훅을 활용하면 컴포넌트의 상태를 제어하고, API 호출, 이벤트 리스너 등록 등을 수행할 수 있습니다.
생명주기 단계
Vue 컴포넌트의 생명주기는 다음과 같은 주요 단계로 나뉩니다:
- 생성(Creation): 컴포넌트 인스턴스가 생성됩니다
- 마운트(Mounting): 컴포넌트가 DOM에 추가됩니다
- 업데이트(Updating): 컴포넌트의 데이터가 변경되어 다시 렌더링됩니다
- 파괴(Destroying): 컴포넌트가 DOM에서 제거됩니다
생명주기 다이어그램
인스턴스 생성 시작
↓
beforeCreate
↓
데이터 관찰 설정
↓
created
↓
템플릿 컴파일
↓
beforeMount
↓
DOM에 마운트
↓
mounted
↓
데이터 변경 감지
↓
beforeUpdate
↓
DOM 재렌더링
↓
updated
↓
컴포넌트 파괴
↓
beforeDestroy
↓
destroyed생명주기 훅
Vue.js에서 제공하는 생명주기 훅은 다음과 같습니다:
| beforeCreate | 인스턴스가 생성되기 전에 호출됩니다. 데이터 관찰 및 이벤트 설정이 이루어지기 전입니다 | 플러그인 초기화, 전역 설정 |
| created | 인스턴스가 생성된 후에 호출됩니다. 데이터 관찰 및 이벤트 설정이 완료된 후입니다 | API 호출, 데이터 초기화 |
| beforeMount | DOM에 마운트되기 전에 호출됩니다 | 렌더링 전 마지막 설정 |
| mounted | DOM에 마운트된 후에 호출됩니다. 컴포넌트가 화면에 표시된 후입니다 | DOM 조작, 외부 라이브러리 초기화 |
| beforeUpdate | 데이터 변경으로 인해 업데이트되기 전에 호출됩니다 | 업데이트 전 상태 저장 |
| updated | 데이터 변경 후에 호출됩니다. DOM이 업데이트된 후입니다 | DOM 업데이트 후 작업 |
| beforeDestroy | 컴포넌트가 파괴되기 전에 호출됩니다 | 이벤트 리스너 제거, 타이머 정리 |
| destroyed | 컴포넌트가 파괴된 후에 호출됩니다 | 최종 정리 작업 |
Options API에서 생명주기 훅 사용하기
기본 사용법
{{ message }}
카운터: {{ counter }}
증가
export default {
name: 'LifecycleExample',
data() {
return {
message: 'Hello, Vue!',
counter: 0,
timer: null
};
},
beforeCreate() {
console.log('beforeCreate: 컴포넌트가 생성되기 전에 호출됩니다.');
// 이 시점에서는 data, computed, methods에 접근할 수 없습니다
console.log('data 접근 가능?', this.message); // undefined
},
created() {
console.log('created: 컴포넌트가 생성된 후 호출됩니다.');
console.log('data 접근 가능?', this.message); // "Hello, Vue!"
// API 호출 예시
this.fetchData();
},
beforeMount() {
console.log('beforeMount: DOM에 마운트되기 전에 호출됩니다.');
console.log('$el 접근 가능?', this.$el); // undefined
},
mounted() {
console.log('mounted: DOM에 마운트된 후 호출됩니다.');
console.log('$el 접근 가능?', this.$el); // DOM 요소
// DOM 조작이나 외부 라이브러리 초기화
this.initializeTimer();
},
beforeUpdate() {
console.log('beforeUpdate: 업데이트 되기 전에 호출됩니다.');
console.log('업데이트 전 counter 값:', this.counter);
},
updated() {
console.log('updated: 업데이트 된 후 호출됩니다.');
console.log('업데이트 후 counter 값:', this.counter);
},
beforeDestroy() {
console.log('beforeDestroy: 컴포넌트가 파괴되기 전에 호출됩니다.');
// 정리 작업
if (this.timer) {
clearInterval(this.timer);
}
},
destroyed() {
console.log('destroyed: 컴포넌트가 파괴된 후 호출됩니다.');
},
methods: {
increment() {
this.counter++;
},
async fetchData() {
try {
// API 호출 시뮬레이션
const response = await fetch('/api/data');
const data = await response.json();
console.log('데이터 로드 완료:', data);
} catch (error) {
console.error('데이터 로드 실패:', error);
}
},
initializeTimer() {
this.timer = setInterval(() => {
console.log('타이머 실행 중...');
}, 5000);
}
}
};
Composition API에서 생명주기 훅 사용하기
Vue 3의 Composition API에서는 생명주기 훅을 함수로 import하여 사용합니다:
{{ message }}
카운터: {{ counter }}
증가
import {
ref,
onBeforeMount,
onMounted,
onBeforeUpdate,
onUpdated,
onBeforeUnmount,
onUnmounted
} from 'vue'
// 반응형 데이터
const message = ref('Hello, Vue 3!')
const counter = ref(0)
let timer = null
// setup() 함수 자체가 created 훅과 유사한 역할
console.log('setup: 컴포넌트 설정 단계')
// 생명주기 훅 등록
onBeforeMount(() => {
console.log('onBeforeMount: DOM에 마운트되기 전')
})
onMounted(() => {
console.log('onMounted: DOM에 마운트된 후')
// DOM 조작이나 외부 라이브러리 초기화
initializeTimer()
// API 호출
fetchData()
})
onBeforeUpdate(() => {
console.log('onBeforeUpdate: 업데이트 전')
console.log('업데이트 전 counter 값:', counter.value)
})
onUpdated(() => {
console.log('onUpdated: 업데이트 후')
console.log('업데이트 후 counter 값:', counter.value)
})
onBeforeUnmount(() => {
console.log('onBeforeUnmount: 컴포넌트 언마운트 전')
// 정리 작업
if (timer) {
clearInterval(timer)
timer = null
}
})
onUnmounted(() => {
console.log('onUnmounted: 컴포넌트 언마운트 후')
})
// 메서드 정의
const increment = () => {
counter.value++
}
const fetchData = async () => {
try {
const response = await fetch('/api/data')
const data = await response.json()
console.log('데이터 로드 완료:', data)
} catch (error) {
console.error('데이터 로드 실패:', error)
}
}
const initializeTimer = () => {
timer = setInterval(() => {
console.log('타이머 실행 중...')
}, 5000)
}
실제 사용 사례
API 데이터 로딩
로딩 중...
{{ error }}
사용자 목록
{{ user.name }} - {{ user.email }}
import { ref, onMounted } from 'vue'
const users = ref([])
const loading = ref(true)
const error = ref(null)
onMounted(async () => {
try {
const response = await fetch('/api/users')
if (!response.ok) {
throw new Error('사용자 데이터를 불러올 수 없습니다')
}
users.value = await response.json()
} catch (err) {
error.value = err.message
} finally {
loading.value = false
}
})
이벤트 리스너 관리
윈도우 크기: {{ windowSize.width }} x {{ windowSize.height }}
스크롤 위치: {{ scrollPosition }}
import { ref, onMounted, onBeforeUnmount } from 'vue'
const windowSize = ref({ width: 0, height: 0 })
const scrollPosition = ref(0)
const updateWindowSize = () => {
windowSize.value = {
width: window.innerWidth,
height: window.innerHeight
}
}
const updateScrollPosition = () => {
scrollPosition.value = window.scrollY
}
onMounted(() => {
// 초기값 설정
updateWindowSize()
updateScrollPosition()
// 이벤트 리스너 등록
window.addEventListener('resize', updateWindowSize)
window.addEventListener('scroll', updateScrollPosition)
})
onBeforeUnmount(() => {
// 이벤트 리스너 제거 (메모리 누수 방지)
window.removeEventListener('resize', updateWindowSize)
window.removeEventListener('scroll', updateScrollPosition)
})
타이머와 인터벌 관리
실시간 시계
{{ currentTime }}
{{ isRunning ? '정지' : '시작' }}
import { ref, onMounted, onBeforeUnmount } from 'vue'
const currentTime = ref('')
const isRunning = ref(true)
let timer = null
const updateTime = () => {
currentTime.value = new Date().toLocaleTimeString()
}
const startTimer = () => {
timer = setInterval(updateTime, 1000)
isRunning.value = true
}
const stopTimer = () => {
if (timer) {
clearInterval(timer)
timer = null
}
isRunning.value = false
}
const toggleTimer = () => {
if (isRunning.value) {
stopTimer()
} else {
startTimer()
}
}
onMounted(() => {
updateTime() // 초기 시간 설정
startTimer() // 타이머 시작
})
onBeforeUnmount(() => {
stopTimer() // 컴포넌트 제거 시 타이머 정리
})
생명주기 훅 사용 시 주의사항
화살표 함수 사용 금지
// 잘못된 사용법
export default {
mounted: () => {
console.log(this) // undefined! this 바인딩이 안됨
}
}
// 올바른 사용법
export default {
mounted() {
console.log(this) // 컴포넌트 인스턴스
}
}비동기 작업 처리
// 잘못된 사용법
export default {
async mounted() {
// mounted 훅 자체를 async로 만들면 안됨
}
}
// 올바른 사용법
export default {
mounted() {
this.loadData()
},
methods: {
async loadData() {
// 별도 메서드에서 비동기 처리
const data = await fetch('/api/data')
this.data = await data.json()
}
}
}메모리 누수 방지
export default {
mounted() {
// 이벤트 리스너 등록
window.addEventListener('scroll', this.handleScroll)
// 타이머 설정
this.timer = setInterval(this.updateData, 1000)
},
beforeDestroy() {
// 반드시 정리 작업 수행
window.removeEventListener('scroll', this.handleScroll)
if (this.timer) {
clearInterval(this.timer)
}
}
}결론
Vue.js의 생명주기와 훅을 이해하면 컴포넌트의 상태와 동작을 효과적으로 관리할 수 있습니다. 각 생명주기 훅을 적절히 활용하여 API 호출, 이벤트 리스너 등록 및 정리 작업 등을 수행할 수 있습니다.
훅을 콜백(Callback)과 비슷하다고 생각할 수도 있지만, 둘은 다릅니다. 훅은 특정 생명주기나 상태 변화에 반응하여 자동으로 실행되고 사용자가 명시적으로 호출하지 않으며, 프레임워크가 관리합니다. 반면에 콜백은 특정 조건이 충족되면 명시적으로 호출되고 사용자가 정의한 함수이며, 비동기 작업이나 이벤트에 의해 트리거됩니다.
핵심 포인트:
- 생명주기 단계별 적절한 훅 선택으로 효율적인 컴포넌트 관리
- created/mounted에서 초기화 작업 수행
- beforeDestroy/onBeforeUnmount에서 정리 작업 필수
- Composition API의 setup()이 created 훅 역할 수행
- 메모리 누수 방지를 위한 이벤트 리스너와 타이머 정리
생명주기 훅을 올바르게 활용하면 Vue.js 애플리케이션의 성능과 안정성을 크게 향상시킬 수 있습니다.
Vue 폼 바인딩 완벽 가이드 – v-model로 쉽고 강력하게 폼 데이터 관리하기
Vue.js에서 폼 바인딩은 사용자 입력과 데이터 상태를 쉽고 강력하게 동기화할 수 있는 핵심 기능입니다. v-model 디렉티브를 활용하면 텍스트 입력, 체크박스, 라디오 버튼, 셀렉트 박스 등 다양한
hoosfa.tistory.com
'IT기술 > 뷰.js (vue.js)' 카테고리의 다른 글
| Vue.js ref 완벽 가이드: DOM 요소와 컴포넌트 인스턴스 접근하기 (0) | 2025.07.05 |
|---|---|
| Vue.js 감시자(Watchers) 완벽 가이드: 데이터 변화 감지와 반응형 프로그래밍 (0) | 2025.07.05 |
| Vue 폼 바인딩 완벽 가이드 – v-model로 쉽고 강력하게 폼 데이터 관리하기 (0) | 2025.04.30 |
| [Vue] 뷰 이벤트 핸들링 완벽 가이드 (0) | 2025.04.28 |
| Vue.js 리스트 처리: v-for 디렉티브 완벽 가이드 (0) | 2025.04.27 |