레슨 5 / 9·20분
라이프사이클과 Composables
컴포넌트 라이프사이클
Vue 컴포넌트는 생성 → 마운트 → 업데이트 → 언마운트 순서의 라이프사이클을 거칩니다. Composition API에서는 onMounted, onUpdated, onUnmounted 등의 훅으로 각 단계에 로직을 삽입합니다.
vue
<script setup lang="ts">
import {
ref, onMounted, onUpdated, onUnmounted, onBeforeUnmount
} from 'vue';
const data = ref(null);
const timer = ref<number | null>(null);
// 마운트 후 — DOM에 접근 가능, API 호출 등
onMounted(() => {
console.log('컴포넌트가 DOM에 마운트됨');
fetchData();
timer.value = window.setInterval(() => {
console.log('폴링 중...');
}, 5000);
});
// 업데이트 후
onUpdated(() => {
console.log('반응형 데이터 변경으로 DOM 업데이트됨');
});
// 언마운트 전 — 정리 작업
onBeforeUnmount(() => {
if (timer.value) {
clearInterval(timer.value);
}
console.log('타이머 정리 완료');
});
async function fetchData() {
const res = await fetch('/api/data');
data.value = await res.json();
}
</script>Composables (커스텀 합성 함수)
Composable은 Composition API를 활용해 재사용 가능한 상태 로직을 추출하는 함수입니다. React의 커스텀 Hook과 유사한 패턴으로, use 접두사를 붙여 이름짓는 것이 관례입니다.
typescript
// composables/useFetch.ts
import { ref, watchEffect } from 'vue';
export function useFetch<T>(url: string) {
const data = ref<T | null>(null);
const error = ref<string | null>(null);
const loading = ref(true);
async function execute() {
loading.value = true;
error.value = null;
try {
const res = await fetch(url);
if (!res.ok) throw new Error("HTTP " + res.status);
data.value = await res.json();
} catch (e: any) {
error.value = e.message;
} finally {
loading.value = false;
}
}
execute();
return { data, error, loading, refetch: execute };
}vue
<!-- 컴포넌트에서 composable 사용 -->
<script setup lang="ts">
import { useFetch } from '@/composables/useFetch';
type User = { id: number; name: string; email: string };
const { data: users, loading, error } = useFetch<User[]>('/api/users');
</script>
<template>
<div v-if="loading">로딩 중...</div>
<div v-else-if="error">에러: {{ error }}</div>
<ul v-else>
<li v-for="user in users" :key="user.id">
{{ user.name }} ({{ user.email }})
</li>
</ul>
</template>typescript
// composables/useLocalStorage.ts
import { ref, watch } from 'vue';
export function useLocalStorage<T>(key: string, defaultValue: T) {
const stored = localStorage.getItem(key);
const data = ref<T>(stored ? JSON.parse(stored) : defaultValue);
watch(data, (newVal) => {
localStorage.setItem(key, JSON.stringify(newVal));
}, { deep: true });
return data;
}
// 사용
const settings = useLocalStorage('settings', {
theme: 'light',
fontSize: 14,
});💡
Composable 안에서 onMounted, watch 등 라이프사이클 훅과 반응형 API를 자유롭게 사용할 수 있습니다. 각 컴포넌트에서 호출될 때마다 독립적인 상태가 생성되므로 상태 충돌 걱정이 없습니다.