라이프사이클 — 컴포넌트의 탄생부터 소멸까지
React에서는 useEffect 하나로 모든 라이프사이클을 처리하는데, Svelte는 용도별로 나눠져 있어서 의도가 더 명확합니다.
개념 정의
라이프사이클(Lifecycle) 은 컴포넌트가 생성되고, 화면에 마운트되고, 업데이트되고, 제거되는 일련의 과정입니다. Svelte 5에서는 $effect가 주된 라이프사이클 도구이며, onMount와 onDestroy도 여전히 사용됩니다.
라이프사이클 단계
생성 (Initialization)
↓
마운트 (Mount) — DOM에 삽입
↓
업데이트 (Update) — 상태 변경 시 반복
↓
소멸 (Destroy) — DOM에서 제거
onMount — 마운트 시점
<script>
import { onMount } from 'svelte';
let data = $state(null);
let canvas = $state(null);
// DOM이 마운트된 직후 실행
onMount(() => {
console.log('컴포넌트가 마운트되었습니다');
// API 호출 — 가장 흔한 사용 사례
fetch('/api/data')
.then(r => r.json())
.then(d => data = d);
// 정리 함수 반환 가능 (onDestroy 대체)
return () => {
console.log('컴포넌트가 제거됩니다');
};
});
// Canvas 초기화 — DOM 요소가 필요한 작업
onMount(() => {
if (canvas) {
const ctx = canvas.getContext('2d');
ctx.fillStyle = '#ff3e00';
ctx.fillRect(0, 0, 100, 100);
}
});
</script>
<canvas bind:this={canvas} width="200" height="200"></canvas>
**핵심 **: onMount는 ** 서버 사이드 렌더링(SSR) 시에는 실행되지 않습니다 **. 브라우저 전용 API(DOM, window, localStorage 등)를 안전하게 사용할 수 있는 지점입니다.
onDestroy — 소멸 시점
<script>
import { onDestroy } from 'svelte';
let count = $state(0);
// 타이머 설정
const interval = setInterval(() => {
count++;
}, 1000);
// 컴포넌트가 제거될 때 타이머 정리
onDestroy(() => {
clearInterval(interval);
console.log('타이머 정리 완료');
});
</script>
<p>경과 시간: {count}초</p>
$effect로 라이프사이클 관리
Svelte 5에서는 $effect가 대부분의 라이프사이클 시나리오를 처리합니다.
<script>
let count = $state(0);
let query = $state('');
// 마운트 시 + 의존성 변경 시 실행
$effect(() => {
console.log('count가 변경됨:', count);
});
// 정리 함수로 언마운트 처리
$effect(() => {
const handler = (e) => console.log('키 입력:', e.key);
window.addEventListener('keydown', handler);
// 정리 — 다음 실행 전 또는 언마운트 시 호출
return () => {
window.removeEventListener('keydown', handler);
};
});
// 디바운스 패턴
$effect(() => {
if (!query) return;
const timeout = setTimeout(async () => {
const res = await fetch(`/api/search?q=${query}`);
console.log(await res.json());
}, 300);
return () => clearTimeout(timeout);
});
</script>
$effect.pre — DOM 업데이트 전
<script>
let messages = $state([]);
let chatContainer = $state(null);
// DOM이 업데이트되기 전에 실행
$effect.pre(() => {
// 새 메시지 추가 전 스크롤 위치 기록
if (chatContainer) {
const isAtBottom =
chatContainer.scrollHeight - chatContainer.scrollTop ===
chatContainer.clientHeight;
// DOM 업데이트 후 스크롤 유지를 위한 준비
if (isAtBottom) {
// tick() 후에 스크롤 이동하는 로직
}
}
});
</script>
tick() — 다음 DOM 업데이트 대기
<script>
import { tick } from 'svelte';
let text = $state('');
let textArea = $state(null);
async function handleInput() {
text = text.toUpperCase();
// DOM 업데이트가 완료될 때까지 대기
await tick();
// DOM이 업데이트된 후의 작업
textArea?.setSelectionRange(text.length, text.length);
}
</script>
<textarea bind:this={textArea} bind:value={text} oninput={handleInput}></textarea>
onMount vs $effect
| 특성 | onMount | $effect |
|---|---|---|
| 실행 시점 | 마운트 시 1회 | 마운트 시 + 의존성 변경 시 |
| SSR 실행 | X | X (브라우저에서만) |
| 의존성 추적 | 없음 | 자동 |
| 정리 함수 | 반환 가능 | 반환 가능 |
| 주 용도 | 초기화, API 호출 | 반응형 부수 효과 |
<script>
import { onMount } from 'svelte';
let userId = $state(1);
let userData = $state(null);
// onMount — 최초 1회만 실행
onMount(() => {
console.log('컴포넌트 마운트됨');
});
// $effect — userId가 바뀔 때마다 다시 실행
$effect(() => {
fetch(`/api/users/${userId}`)
.then(r => r.json())
.then(d => userData = d);
});
</script>
실전 패턴 — 인터섹션 옵저버
<script>
import { onMount } from 'svelte';
let element = $state(null);
let isVisible = $state(false);
onMount(() => {
const observer = new IntersectionObserver(
([entry]) => {
isVisible = entry.isIntersecting;
},
{ threshold: 0.5 }
);
if (element) observer.observe(element);
return () => observer.disconnect();
});
</script>
<div bind:this={element} class:visible={isVisible}>
{isVisible ? '화면에 보임!' : '화면 밖'}
</div>
<style>
div {
opacity: 0;
transform: translateY(20px);
transition: all 0.5s;
}
.visible {
opacity: 1;
transform: translateY(0);
}
</style>
면접 포인트
- "onMount와 $effect의 차이는?": onMount는 마운트 시 1회만 실행되고, $effect는 의존성이 바뀔 때마다 재실행됩니다. 초기 설정은 onMount, 반응형 로직은 $effect를 사용합니다.
- "SSR에서 onMount가 실행되지 않는 이유는?": onMount는 브라우저 DOM이 준비된 후 실행되도록 설계되었습니다. SSR 환경에는 DOM이 없으므로 건너뜁니다. 서버에서 데이터가 필요하면 SvelteKit의 load 함수를 사용해야 합니다.
정리
Svelte의 라이프사이클은 심플합니다. onMount로 초기화하고, $effect로 반응형 부수 효과를 관리하고, 정리 함수로 리소스를 해제하면 됩니다. React의 useEffect처럼 하나의 함수에 모든 것을 우겨 넣을 필요 없이, 의도에 맞는 도구를 골라 쓸 수 있습니다.
댓글 로딩 중...