Lifecycle Hooks
생명주기 훅은 컴포넌트가 생성되고, DOM에 마운트되고, 업데이트되고, 파괴되는 각 단계에서 실행되는 콜백 함수입니다.
면접에서 "API 호출은 어떤 생명주기에서 하나요?"라는 질문이 나오면, 단순히 "onMounted"라고 답하는 것보다 왜 그 시점인지 를 설명할 수 있어야 합니다.
생명주기 전체 흐름
setup()
↓
onBeforeMount → DOM 생성 직전
↓
onMounted → DOM에 마운트 완료
↓
(반응형 데이터 변경 시)
onBeforeUpdate → DOM 업데이트 직전
↓
onUpdated → DOM 업데이트 완료
↓
(컴포넌트 제거 시)
onBeforeUnmount → DOM에서 제거 직전
↓
onUnmounted → DOM에서 제거 완료
각 훅의 역할과 사용 예시
<script setup lang="ts">
import {
onBeforeMount,
onMounted,
onBeforeUpdate,
onUpdated,
onBeforeUnmount,
onUnmounted,
ref
} from 'vue'
const count = ref(0)
const containerRef = ref<HTMLDivElement>()
// --- 마운트 단계 ---
onBeforeMount(() => {
// DOM이 아직 생성되지 않음
// 서버사이드 렌더링에서도 호출됨
console.log('마운트 직전 — DOM 없음')
console.log(containerRef.value) // undefined
})
onMounted(() => {
// DOM에 마운트 완료 — DOM 접근 가능
// API 호출, 이벤트 리스너 등록, 타이머 설정
console.log('마운트 완료 — DOM 접근 가능')
console.log(containerRef.value) // <div>...</div>
// 실전: API 호출
// fetchData()
// 실전: DOM 기반 라이브러리 초기화
// initChart(containerRef.value)
})
// --- 업데이트 단계 ---
onBeforeUpdate(() => {
// 반응형 데이터가 변경되어 DOM이 업데이트되기 직전
console.log('업데이트 직전 — 이전 DOM 상태')
})
onUpdated(() => {
// DOM 업데이트 완료
// 주의: 여기서 상태를 변경하면 무한 루프 위험!
console.log('업데이트 완료 — 새로운 DOM 상태')
})
// --- 언마운트 단계 ---
onBeforeUnmount(() => {
// 컴포넌트가 DOM에서 제거되기 직전
// 아직 DOM에 접근 가능
console.log('언마운트 직전')
})
onUnmounted(() => {
// 컴포넌트가 DOM에서 완전히 제거됨
// 클린업: 이벤트 리스너 제거, 타이머 정리, 구독 해제
console.log('언마운트 완료')
})
</script>
<template>
<div ref="containerRef">
<p>{{ count }}</p>
<button @click="count++">증가</button>
</div>
</template>
실전 활용 패턴
이벤트 리스너 등록/해제
<script setup lang="ts">
import { onMounted, onUnmounted, ref } from 'vue'
const scrollY = ref(0)
const handleScroll = () => {
scrollY.value = window.scrollY
}
onMounted(() => {
window.addEventListener('scroll', handleScroll)
})
onUnmounted(() => {
// 메모리 누수 방지 — 반드시 해제
window.removeEventListener('scroll', handleScroll)
})
</script>
타이머 정리
<script setup lang="ts">
import { onMounted, onUnmounted, ref } from 'vue'
const elapsed = ref(0)
let intervalId: ReturnType<typeof setInterval>
onMounted(() => {
intervalId = setInterval(() => {
elapsed.value++
}, 1000)
})
onUnmounted(() => {
// 타이머 정리 — 컴포넌트가 사라져도 타이머가 남아있으면 메모리 누수
clearInterval(intervalId)
})
</script>
외부 라이브러리 초기화/정리
<script setup lang="ts">
import { onMounted, onUnmounted, ref } from 'vue'
const chartRef = ref<HTMLCanvasElement>()
let chartInstance: any = null
onMounted(() => {
if (chartRef.value) {
// 차트 라이브러리 초기화 (DOM 필요)
// chartInstance = new Chart(chartRef.value, config)
}
})
onUnmounted(() => {
// 차트 인스턴스 정리
chartInstance?.destroy()
chartInstance = null
})
</script>
<template>
<canvas ref="chartRef"></canvas>
</template>
Options API vs Composition API 훅 매핑
| Options API | Composition API | 설명 |
|---|---|---|
beforeCreate | setup() 자체 | 인스턴스 초기화 전 |
created | setup() 자체 | 인스턴스 초기화 후 |
beforeMount | onBeforeMount | DOM 생성 직전 |
mounted | onMounted | DOM 마운트 완료 |
beforeUpdate | onBeforeUpdate | DOM 업데이트 직전 |
updated | onUpdated | DOM 업데이트 완료 |
beforeUnmount | onBeforeUnmount | 언마운트 직전 |
unmounted | onUnmounted | 언마운트 완료 |
beforeCreate와 created는 Composition API에서 별도 훅이 없습니다. setup() 자체가 두 훅 사이에서 실행되므로, setup 안에 직접 코드를 작성하면 됩니다.
특수 생명주기 훅
<script setup lang="ts">
import {
onActivated,
onDeactivated,
onErrorCaptured,
onRenderTracked,
onRenderTriggered
} from 'vue'
// KeepAlive 관련
onActivated(() => {
// KeepAlive로 캐시된 컴포넌트가 다시 활성화될 때
console.log('활성화됨')
})
onDeactivated(() => {
// KeepAlive로 캐시된 컴포넌트가 비활성화될 때
console.log('비활성화됨')
})
// 에러 처리
onErrorCaptured((error, instance, info) => {
console.error('자식 컴포넌트 에러:', error)
console.log('에러 발생 위치:', info)
// false를 반환하면 에러 전파를 중단
return false
})
// 디버깅 전용 (개발 모드에서만)
onRenderTracked((event) => {
// 반응형 의존성이 추적될 때
console.log('추적:', event)
})
onRenderTriggered((event) => {
// 반응형 의존성이 변경되어 리렌더링이 트리거될 때
console.log('트리거:', event)
})
</script>
SSR에서의 생명주기
<script setup lang="ts">
import { onMounted, onServerPrefetch } from 'vue'
// SSR 전용 훅 — 서버에서 컴포넌트 렌더링 전 데이터 프리페치
onServerPrefetch(async () => {
// 서버에서만 실행됨
// await fetchData()
})
onMounted(() => {
// 클라이언트에서만 실행됨!
// SSR 환경에서는 호출되지 않음
})
</script>
면접에서 자주 묻는 질문
Q: API 호출은 어디서 해야 하나요?
onMounted에서 하는 것이 일반적입니다. 이유:
- SSR에서는 서버와 클라이언트 양쪽 실행을 피하기 위해
- DOM 접근이 필요한 후속 처리가 있을 수 있으므로
- setup에서 해도 동작하지만, SSR 환경에서의 일관성을 위해 onMounted가 권장됨
Q: 왜 onUpdated에서 상태를 변경하면 안 되나요?
상태 변경 → DOM 업데이트 → onUpdated 호출 → 상태 변경 → ... 무한 루프에 빠질 수 있습니다.
Q: onUnmounted에서 꼭 정리해야 하는 것은?
이벤트 리스너, 타이머(setInterval/setTimeout), WebSocket 연결, 외부 라이브러리 인스턴스 등 — 자동으로 정리되지 않는 것들입니다.
면접 팁
- 생명주기 다이어그램을 그려서 설명할 수 있으면 확실한 플러스입니다
setup()이beforeCreate와created사이에서 실행된다는 것을 알면 두 API의 관계를 정확히 이해하고 있다는 인상을 줍니다- ** 메모리 누수 방지 **를 위한 클린업 패턴을 구체적으로 설명할 수 있으면 실무 역량을 보여줄 수 있습니다
요약
Vue의 생명주기는 마운트, 업데이트, 언마운트 세 단계로 나뉩니다. onMounted에서 API 호출과 DOM 기반 초기화를 하고, onUnmounted에서 반드시 클린업을 수행하세요. Composition API에서는 setup() 자체가 beforeCreate/created를 대체합니다.
댓글 로딩 중...