생명주기 훅은 컴포넌트가 생성되고, DOM에 마운트되고, 업데이트되고, 파괴되는 각 단계에서 실행되는 콜백 함수입니다.

면접에서 "API 호출은 어떤 생명주기에서 하나요?"라는 질문이 나오면, 단순히 "onMounted"라고 답하는 것보다 왜 그 시점인지 를 설명할 수 있어야 합니다.


생명주기 전체 흐름

PLAINTEXT
setup()

onBeforeMount     → DOM 생성 직전

onMounted         → DOM에 마운트 완료

(반응형 데이터 변경 시)
onBeforeUpdate    → DOM 업데이트 직전

onUpdated         → DOM 업데이트 완료

(컴포넌트 제거 시)
onBeforeUnmount   → DOM에서 제거 직전

onUnmounted       → DOM에서 제거 완료

각 훅의 역할과 사용 예시

VUE
<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>

실전 활용 패턴

이벤트 리스너 등록/해제

VUE
<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>

타이머 정리

VUE
<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>

외부 라이브러리 초기화/정리

VUE
<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 APIComposition API설명
beforeCreatesetup() 자체인스턴스 초기화 전
createdsetup() 자체인스턴스 초기화 후
beforeMountonBeforeMountDOM 생성 직전
mountedonMountedDOM 마운트 완료
beforeUpdateonBeforeUpdateDOM 업데이트 직전
updatedonUpdatedDOM 업데이트 완료
beforeUnmountonBeforeUnmount언마운트 직전
unmountedonUnmounted언마운트 완료

beforeCreatecreated는 Composition API에서 별도 훅이 없습니다. setup() 자체가 두 훅 사이에서 실행되므로, setup 안에 직접 코드를 작성하면 됩니다.


특수 생명주기 훅

VUE
<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에서의 생명주기

VUE
<script setup lang="ts">
import { onMounted, onServerPrefetch } from 'vue'

// SSR 전용 훅 — 서버에서 컴포넌트 렌더링 전 데이터 프리페치
onServerPrefetch(async () => {
  // 서버에서만 실행됨
  // await fetchData()
})

onMounted(() => {
  // 클라이언트에서만 실행됨!
  // SSR 환경에서는 호출되지 않음
})
</script>

면접에서 자주 묻는 질문

Q: API 호출은 어디서 해야 하나요?

onMounted에서 하는 것이 일반적입니다. 이유:

  1. SSR에서는 서버와 클라이언트 양쪽 실행을 피하기 위해
  2. DOM 접근이 필요한 후속 처리가 있을 수 있으므로
  3. setup에서 해도 동작하지만, SSR 환경에서의 일관성을 위해 onMounted가 권장됨

Q: 왜 onUpdated에서 상태를 변경하면 안 되나요?

상태 변경 → DOM 업데이트 → onUpdated 호출 → 상태 변경 → ... 무한 루프에 빠질 수 있습니다.

Q: onUnmounted에서 꼭 정리해야 하는 것은?

이벤트 리스너, 타이머(setInterval/setTimeout), WebSocket 연결, 외부 라이브러리 인스턴스 등 — 자동으로 정리되지 않는 것들입니다.


면접 팁

  • 생명주기 다이어그램을 그려서 설명할 수 있으면 확실한 플러스입니다
  • setup()beforeCreatecreated 사이에서 실행된다는 것을 알면 두 API의 관계를 정확히 이해하고 있다는 인상을 줍니다
  • ** 메모리 누수 방지 **를 위한 클린업 패턴을 구체적으로 설명할 수 있으면 실무 역량을 보여줄 수 있습니다

요약

Vue의 생명주기는 마운트, 업데이트, 언마운트 세 단계로 나뉩니다. onMounted에서 API 호출과 DOM 기반 초기화를 하고, onUnmounted에서 반드시 클린업을 수행하세요. Composition API에서는 setup() 자체가 beforeCreate/created를 대체합니다.

댓글 로딩 중...