[Vue.js] ๋ผ์ดํ์ฌ์ดํด ํ (Lifecycle Hooks)
ํฌ์คํ ์ด์ ์ ์์
๐ก Vue.js์ ๋ผ์ดํ์ฌ์ดํด(Lifecycle)์ด๋?
Vue ์ปดํฌ๋ํธ๋ ๋จ์ํ ํ ๋ฒ ๋ง๋ค์ด์ง๊ณ ๋๋๋ ๊ฒ ์๋๋ผ, ํ์๋ถํฐ ์๋ฉธ๊น์ง ์ผ๋ จ์ ๋จ๊ณ๋ฅผ ๊ฑฐ์นฉ๋๋ค.
์ด ๊ณผ์ ์ ์ปดํฌ๋ํธ ์๋ช ์ฃผ๊ธฐ(Lifecycle)๋ผ๊ณ ๋ถ๋ฆ ๋๋ค.
์ฝ๊ฒ ๋งํ๋ฉด, ์ปดํฌ๋ํธ๊ฐ
์์ฑ๋๊ณ (create), DOM์ ๋ถ๊ณ (mount), ์ ๋ฐ์ดํธ๋๊ณ (update), ์ฌ๋ผ์ง๊ธฐ๊น์ง (unmount)
์ด ์ ์ฒด ํ๋ฆ์ Vue๊ฐ ๋ด๋ถ์ ์ผ๋ก ๊ด๋ฆฌํ๊ณ ์์ผ๋ฉฐ, ๊ฐ์ฅ ์ค์ํ ์์๋
ํน์ ์์ ๋ง๋ค ์คํํ ์ฝ๋๋ฅผ ์ง์ ์์ฑํ ์ ์๋ค๋ ๊ฒ์ ๋๋ค.
์ด๋ ์ฌ์ฉํ๋ ๊ฒ ๋ฐ๋ก! ๋ผ์ดํ์ฌ์ดํด ํ (Lifecycle Hooks) ์ ๋๋ค.
Vue 3์์๋ ์ปดํฌ๋ํธ์ ์๋ช ์ฃผ๊ธฐ ๋์ ํน์ ์์ ์ ์คํํ ์ ์๋ ๋ผ์ดํ์ฌ์ดํด ํ (Lifecycle Hooks)์ ์ ๊ณตํฉ๋๋ค.
์์ Vue 2์์๋ created, mounted, destroyed ๊ฐ์ ์ต์ ์ ์ฌ์ฉํ์ง๋ง,
Vue 3์ <script setup> ๋ฌธ๋ฒ์์๋ ์กฐ๊ธ ๋ค๋ฅด๊ฒ ์ฌ์ฉํฉ๋๋ค.
์ด๋ฒ ๊ธ์์๋ ์์ฃผ ์ฐ์ด๋ ํ ๋ค๊ณผ, ์ค์ ํ๋ก์ ํธ์์ ์ด๋ป๊ฒ ํ์ฉํ๋์ง ๊ฐ๋จํ ์์ ์ ํจ๊ป ์ ๋ฆฌํด๋ณด์์ต๋๋ค.
1. ๊ธฐ๋ณธ ์ฌ์ฉ๋ฒ
<script setup>์ ์ฌ์ฉํ ๋๋ ๋ผ์ดํ์ฌ์ดํด ํ ์ onMounted, onUnmounted, onUpdated ๋ฑ์ ํจ์๋ก ๋ถ๋ฌ์์ ์ฌ์ฉํ๋ฉฐ,
Vue์์ ์ ๊ณตํ๋ vue ๋ชจ๋์์ importํด์ผ ํฉ๋๋ค.
<template>
<div>๋ผ์ดํ์ธ์ดํด ์์ </div>
</template>
<script setup>
import { onMounted } from 'vue'
onMounted(() => {
console.log('## onMounted')
})
</script>
๐จโ๐ป ์คํ๊ฒฐ๊ณผ

์์ ๊ฐ์ด ์ปดํฌ๋ํธ๊ฐ DOM์ ์์ ํ ๋ง์ดํธ ๋ ๋ ํธ์ถ๋๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
2. ์ฃผ์ ๋ผ์ดํ์ฌ์ดํด ํ ์ ๋ฆฌ
์์์๋ onMounted์ ๋ํด์๋ง ํ ์คํธ๋ฅผ ํด๋ณด์์ง๋ง, ์ค์ ๋ก๋ ์์ฃผ ์ฌ์ฉํ๋ ๋ผ์ดํ์ฌ์ดํด ํ ์ด ๋ ์กด์ฌํฉ๋๋ค.
- onBeforeMount
- ์ปดํฌ๋ํธ๊ฐ DOM์ ๋ถ๊ธฐ ์ ์ ํธ์ถ๋ฉ๋๋ค. - onMounted
- ์ปดํฌ๋ํธ๊ฐ DOM์ ์์ ํ ๋ง์ดํธ๋ ํ ํธ์ถ๋ฉ๋๋ค. DOM ์กฐ์์ด๋ ์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฐ๋์ ์์ฃผ ์ฌ์ฉ๋ฉ๋๋ค. - onBeforeUpdate
- ๋ฐ์ํ ์ํ๊ฐ ๋ณ๊ฒฝ๋์ด DOM์ด ์ ๋ฐ์ดํธ๋๊ธฐ ์ง์ ์ ํธ์ถ๋ฉ๋๋ค. - onUpdated
- ๋ฐ์ํ ์ํ ๋ณ๊ฒฝ์ผ๋ก ์ธํด DOM์ด ์ ๋ฐ์ดํธ๋ ์งํ์ ํธ์ถ๋ฉ๋๋ค. - onBeforeUnmount
- ์ปดํฌ๋ํธ๊ฐ DOM์์ ์ ๊ฑฐ๋๊ธฐ ์ง์ ์ ํธ์ถ๋ฉ๋๋ค. - onUnmounted
- ์ปดํฌ๋ํธ๊ฐ ์์ ํ ์ธ๋ง์ดํธ๋ ํ ํธ์ถ๋ฉ๋๋ค. ์ด๋ฒคํธ ๋ฆฌ์ค๋ ํด์ ๊ฐ์ ์ ๋ฆฌ์ ์ ํฉํฉ๋๋ค.
App.vue
<template>
<div>
<button @click="showTest = !showTest">
{{ showTest ? '์ปดํฌ๋ํธ ์ ๊ฑฐ' : '์ปดํฌ๋ํธ ๋ค์ ๋ณด์ฌ์ฃผ๊ธฐ' }}
</button>
<Body v-if="showTest" />
</div>
</template>
<script setup>
import { ref } from 'vue'
import Body from '../components/Body.vue'
const showTest = ref(true)
</script>
Body.vue
<template>
<div>
<h2>๋ผ์ดํ์ฌ์ดํด ํ
์คํธ</h2>
<p>์นด์ดํธ: {{ count }}</p>
<button @click="count++">์นด์ดํธ ์ฆ๊ฐ</button>
</div>
</template>
<script setup>
import {
ref,
onBeforeMount,
onMounted,
onBeforeUpdate,
onUpdated,
onBeforeUnmount,
onUnmounted
} from 'vue'
const count = ref(0)
// ๐ต ์ปดํฌ๋ํธ๊ฐ ์์ง DOM์ ๋ถ๊ธฐ ์ , setup() ๋ค์ ๋จ๊ณ์์ ํธ์ถ๋จ
onBeforeMount(() => {
console.log('๐ต onBeforeMount: DOM์ ๋ถ๊ธฐ ์ง์ ')
})
// ๐ข ์ปดํฌ๋ํธ๊ฐ DOM์ ์์ ํ ๋ง์ดํธ๋ ํ ํธ์ถ๋จ
// ์ด ์์ ์ ์ค์ HTML ์์์ ์ ๊ทผ๊ฐ๋ฅ
onMounted(() => {
console.log('๐ข onMounted: DOM ๋ง์ดํธ ์๋ฃ')
})
// ๐ก ๋ฐ์ํ ์ํ(count ๋ฑ)๊ฐ ๋ณ๊ฒฝ๋์ด DOM์ด ๋ฐ๋๊ธฐ *๋ฐ๋ก ์ *์ ํธ์ถ๋จ
// DOM์ด ๋ฐ๋๊ธฐ ์ง์ ์ ์ํ๋ฅผ ํ์ธํ๊ฑฐ๋, ๋ณ๊ฒฝ ์ง์ ์ฒ๋ฆฌํ ์ผ์ด ์๋ค๋ฉด ์ฌ๊ธฐ์์ ์ฒ๋ฆฌ
onBeforeUpdate(() => {
console.log('๐ก onBeforeUpdate: DOM ์
๋ฐ์ดํธ ์ง์ ')
})
// ๐ ๋ฐ์ํ ์ํ๊ฐ ๋ฐ๋๊ณ ์ค์ DOM๊น์ง ๋ฐ๋ ํ์ ํธ์ถ๋จ
// ๋ณ๊ฒฝ๋ DOM์ ํ์ธํ๊ฑฐ๋ ํ์ฒ๋ฆฌํ ๋ ์ฌ์ฉ๋จ
onUpdated(() => {
console.log('๐ onUpdated: DOM ์
๋ฐ์ดํธ ์๋ฃ')
})
// ๐ด ์ปดํฌ๋ํธ๊ฐ DOM์์ ์ ๊ฑฐ๋๊ธฐ ์ง์ ํธ์ถ๋จ
// ์ ๊ฑฐ ์ ์ ๋ฆฌ์์ค๋ฅผ ์ ๋ฆฌํ๊ฑฐ๋ ์ฌ์ฉ์ ํ์ธ ๋ชจ๋ฌ ๋ฑ์ ๋์ธ ์๋ ์์
onBeforeUnmount(() => {
console.log('๐ด onBeforeUnmount: DOM ์ ๊ฑฐ ์ง์ ')
})
// โซ ์ปดํฌ๋ํธ๊ฐ ์์ ํ ์ ๊ฑฐ๋ ํ ํธ์ถ๋จ
// ์ด๋ฒคํธ ๋ฆฌ์ค๋ ํด์ , ํ์ด๋จธ ์ ๊ฑฐ ๋ฑ ๋ฉ๋ชจ๋ฆฌ ๋์๋ฅผ ๋ฐฉ์งํ๋ ์ ๋ฆฌ ์์
์ ์ ํฉ
onUnmounted(() => {
console.log('โซ onUnmounted: DOM ์ ๊ฑฐ ์๋ฃ')
})
</script>
๐จโ๐ป ์คํ๊ฒฐ๊ณผ
โ 1. ํ๋ฉด์ด ๋ ๋๋ง(mount) ๋์์ ๋
์ปดํฌ๋ํธ๊ฐ ์ฒ์ ์๊ธธ ๋ ํธ์ถ๋ฉ๋๋ค.
onBeforeMount, onMounted

โ 2. ๋ฐ์ํ ์ํ ๋ฑ์ด ๋ณ๊ฒฝ๋์ด ํ๋ฉด์ด ์ ๋ฐ์ดํธ๋ ๋
์นด์ดํธ ํด๋ฆญ ์ ref ๊ฐ(count)์ ์ฆ๊ฐ์ํฌ ๋ ์ํ๊ฐ ๋ณ๊ฒฝ์ด ๋๋ฉด์ ํธ์ถ๋ฉ๋๋ค.
onBeforeUpdate, onUpdated

โ 3. ์ปดํฌ๋ํธ๊ฐ ์ ๊ฑฐ(unmount) ๋ ๋
๋ถ๋ชจ ์ปดํฌ๋ํธ์์ v-if๋ก ํด๋น ์ปดํฌ๋ํธ๋ฅผ ์ ๊ฑฐํ ๋ ํธ์ถ๋ฉ๋๋ค.
onBeforeUnmount, onUnmounted

์ด ์ธ์๋ ์๋์ ๊ฐ์ ๋ผ์ดํ์ฌ์ดํด๋ ์์ผ๋ ์ฐธ๊ณ ํด์ฃผ์ธ์ !
- onActivated
- <keep-alive>๋ก ๊ฐ์ผ ์ปดํฌ๋ํธ๊ฐ ํ์ฑํ๋ ๋ ํธ์ถ๋ฉ๋๋ค. - onDeactivated
- <keep-alive>๋ก ๊ฐ์ผ ์ปดํฌ๋ํธ๊ฐ ๋นํ์ฑํ๋ ๋ ํธ์ถ๋ฉ๋๋ค. - onErrorCaptured
- ํ์ ์ปดํฌ๋ํธ์์ ์ค๋ฅ๊ฐ ๋ฐ์ํ์ ๋ ํธ์ถ๋ฉ๋๋ค. - onRenderTracked
- ๋ฐ์ํ ๋ ๋๋ง ์ ์ด๋ค ๊ฐ์ด ์ถ์ ๋๋์ง ๋๋ฒ๊น ์ฉ์ผ๋ก ํ์ธํ ์ ์์ต๋๋ค. - onRenderTriggered
- ์ด๋ค ๋ฐ์ํ ๊ฐ์ด ๋ณ๊ฒฝ๋์ด ๋ ๋๋ง์ด ํธ๋ฆฌ๊ฑฐ๋์๋์ง ์ถ์ ํ ์ ์์ต๋๋ค.
3. Pinia๋ฅผ ์ฌ์ฉํ ์์
Pinia๋ก ๊ด๋ฆฌํ๋ ์คํ ์ด์ ์ํ ๋ณํ๋ฅผ ๊ฐ์งํ๊ณ , ์ปดํฌ๋ํธ๊ฐ ๋ง์ดํธ๋ ๋ ์ด๊ธฐ ๋ฐ์ดํฐ๋ฅผ ๋ถ๋ฌ์ค๋ ๊ตฌ์กฐ๋ฅผ ์๊ฐํด๋ณผ ์ ์์ต๋๋ค.
<script setup>
import { onMounted } from 'vue'
import { useUserStore } from '@/stores/user'
const userStore = useUserStore()
onMounted(async () => {
await userStore.fetchUserData()
console.log('์ฌ์ฉ์ ์ ๋ณด ๋ถ๋ฌ์ค๊ธฐ ์๋ฃ!')
})
</script>
onMounted ์์์ ๋น๋๊ธฐ๋ก ๋ฐ์ดํฐ๋ฅผ ๋ถ๋ฌ์ค๋ฉด, ์ปดํฌ๋ํธ๊ฐ ํ๋ฉด์ ๋ํ๋ ๋ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ์ด๊ธฐํํ ์ ์์ต๋๋ค.
Vue 3์ ๋ผ์ดํ์ฌ์ดํด ํ ์ ์๊ฐ๋ณด๋ค ๊ฐ๋จํ๊ณ ์ง๊ด์ ์ ๋๋ค.
๊ฐ์ธ์ ์ผ๋ก๋ onMounted์์ ์ด๊ธฐ ๋ฐ์ดํฐ๋ฅผ ๋ถ๋ฌ์ค๋ ํจํด์ ์ฉ์ดํ๊ฒ ์์ฃผ ์ฐ๊ณ ์์ต๋๋ค. ๐