$효과 및 Svelte 5의 수명 주기: 사용 시기(및 사용하지 않을 시기)
다른 것보다 더 많이 오해되고 남용되는 Svelte 5의 Rune이 하나 있다면 그것은 바로 $effect.
React에서 왔습니다. useEffect 종종 각 못에 망치를 사용하고 자연스럽습니다.
Svelte에서 해당 패턴을 복제해 보세요. 하지만 $effect 다른 철학을 가지고 있고,
사용 범위가 더 좁아지고 이를 무시하면 프레임워크의 최악의 안티 패턴이 직접적으로 발생합니다.
이 가이드는 수행하는 작업을 정확하게 정의합니다. $effect, 추적 메커니즘과 같습니다.
자동은 내부적으로 작동하는데, 사용 여부를 결정하는 황금률은 무엇이며,
주요 합법적 사용 사례의 구체적인 예: 분석, WebSocket, 라이브러리와의 통합
타사 및 동기화 localStorage.
$효과의 황금률
글을 쓰기 전에 $effect, 스스로에게 물어보세요. "기존 상태에서 무언가를 계산하고 있습니까?"
대답이 '예'라면 다음을 사용하세요. $derived. $effect 그리고 실제 부작용에 대해서는:
UI 외부 세계와 상호 작용하는 작업(직접 DOM, 네트워크, 저장소, 타이머,
타사 라이브러리).
$ effect 작동 방식: 자동 추적
$effect DOM이 업데이트된 후 함수를 실행합니다. 특징
근본적이고 그 자동으로 모든 $state와 $derived를 추적합니다.
그 실행 이러한 종속성 중 하나가 변경될 때마다 다시 실행됩니다.
종속성을 명시적으로 선언할 필요는 없습니다.
<script lang="ts">
let count = $state(0);
let name = $state('Federico');
// Questo effect dipende da ENTRAMBI count e name
// perche li legge entrambi durante l'esecuzione
$effect(() => {
console.log(`${name} ha un contatore di ${count}`);
// Si ri-esegue quando count O name cambiano
});
// Questo effect dipende SOLO da count
$effect(() => {
document.title = `Contatore: ${count}`;
// Si ri-esegue SOLO quando count cambia
});
</script>
추적 메커니즘은 다음과 동일한 프록시 시스템을 사용합니다. $state: 실행 중
의 $effect, 반응 값에 대한 각 액세스가 기록됩니다. 언제라도
이러한 값이 변경되면 효과는 "더티"로 표시되고 재생이 예약됩니다.
정리 기능
$effect 이전에 실행되는 정리 함수를 반환할 수 있습니다.
다음 번에 효과를 다시 실행할 때와 구성요소가 해체될 때. 이는 필수적입니다.
타이머, 구독, 이벤트 리스너로 메모리 누수를 방지하세요.
<script lang="ts">
let wsUrl = $state('wss://api.example.com/stream');
let messages = $state<string[]>([]);
$effect(() => {
// Effect traccia wsUrl: si ri-esegue se l'URL cambia
const ws = new WebSocket(wsUrl);
ws.addEventListener('message', (event) => {
messages.push(event.data);
});
ws.addEventListener('error', (error) => {
console.error('WebSocket error:', error);
});
// Cleanup: chiude la connessione prima della prossima esecuzione
// e quando il componente viene smontato
return () => {
ws.close();
console.log('WebSocket chiuso');
};
});
</script>
Se wsUrl 변경, Svelte 5가 정리(이전 WS 연결 종료),
그런 다음 효과를 다시 실행합니다(새 URL로 새 연결을 엽니다). 그리고 깔끔한 패턴
수동 수명주기 관리가 필요하지 않습니다.
수명주기 : $ effect 대 onMount 대 onDestroy
Svelte 5는 Svelte 4(onMount, onDestroy,
등) 이전 버전과의 호환성을 위해 룬은 보다 균일한 접근 방식을 제공합니다.
<script lang="ts">
import { onMount, onDestroy } from 'svelte'; // Svelte 4 style
let data = $state(null);
// --- Svelte 4 pattern ---
onMount(async () => {
data = await fetchData();
});
// --- Svelte 5 equivalente con $effect ---
$effect(() => {
// $effect.root per effects che non dipendono da stato
// e si eseguono una sola volta (equivalente di onMount)
fetchData().then(result => {
data = result;
});
return () => {
// cleanup equivalente a onDestroy
};
});
// --- Svelte 5 per operazioni truly una-tantum ---
// Preferisci il blocco di codice nel componente
// o usa untrack() per evitare tracking accidentale
import { untrack } from 'svelte';
$effect(() => {
// untrack impedisce il tracking di initialValue
const initial = untrack(() => data);
console.log('Valore iniziale (non tracciato):', initial);
// count E tracciato perche e fuori da untrack
console.log('Count corrente:', count);
});
</script>
$ effect의 합법적인 사용 사례
다음은 주요 시나리오입니다. $effect 그리고 올바른 선택:
1. localStorage와 동기화
<script lang="ts">
// Leggi il valore iniziale da localStorage (fuori da $effect)
let theme = $state<'light' | 'dark'>(
(localStorage.getItem('theme') as 'light' | 'dark') ?? 'light'
);
// Sincronizza le modifiche a localStorage
$effect(() => {
localStorage.setItem('theme', theme);
document.documentElement.setAttribute('data-theme', theme);
});
</script>
<button onclick={() => theme = theme === 'light' ? 'dark' : 'light'}>
Toggle theme
</button>
2. 분석 및 추적
<script lang="ts">
const { pageId, userId }: { pageId: string; userId?: string } = $props();
// Traccia la visualizzazione di pagina quando pageId cambia
$effect(() => {
// Sia pageId che userId sono tracciati
analytics.track('page_view', {
page: pageId,
user: userId ?? 'anonymous',
timestamp: new Date().toISOString()
});
});
</script>
3. 타사 DOM 라이브러리와의 통합
<script lang="ts">
import Chart from 'chart.js/auto';
let canvasEl: HTMLCanvasElement;
let chartData = $state({ labels: [], datasets: [] });
let chartInstance: Chart | null = null;
$effect(() => {
// Prima esecuzione: crea il chart
if (!chartInstance) {
chartInstance = new Chart(canvasEl, {
type: 'bar',
data: chartData
});
} else {
// Ri-esecuzioni: aggiorna i dati
chartInstance.data = chartData;
chartInstance.update();
}
return () => {
// Cleanup: distruggi il chart
chartInstance?.destroy();
chartInstance = null;
};
});
</script>
<canvas bind:this={canvasEl}></canvas>
4. 교차점 관찰자(지연 로딩, 스크롤 애니메이션)
<script lang="ts">
let element: HTMLElement;
let isVisible = $state(false);
let hasBeenVisible = $state(false);
$effect(() => {
const observer = new IntersectionObserver(
(entries) => {
isVisible = entries[0].isIntersecting;
if (isVisible) hasBeenVisible = true;
},
{ threshold: 0.1 }
);
observer.observe(element);
return () => observer.disconnect();
});
</script>
<div
bind:this={element}
class:visible={isVisible}
class:animated={hasBeenVisible}
>
Contenuto che appare con animazione
</div>
안티 패턴: 계산에 $효과를 사용하지 마세요
가장 일반적인 안티 패턴 $effect 그리고 이를 사용하여 다른 것에서 파생된 상태를 업데이트합니다.
상태. 이로 인해 비효율적이고 잠재적으로 무한한 업데이트 주기가 발생합니다.
<script lang="ts">
let items = $state([1, 2, 3, 4, 5]);
let total = $state(0); // SBAGLIATO: non dovrebbe essere $state
// ANTI-PATTERN: usare $effect per calcolare un valore derivato
$effect(() => {
total = items.reduce((s, i) => s + i, 0);
// Questo crea: items cambia -> effect corre -> total cambia ->
// potenziali altri effects si ri-eseguono inutilmente
});
// CORRETTO: usare $derived
const totalCorrect = $derived(items.reduce((s, i) => s + i, 0));
</script>
<script lang="ts">
let searchQuery = $state('');
let filteredUsers = $state([]); // SBAGLIATO
// ANTI-PATTERN: filtrare con $effect
$effect(() => {
filteredUsers = users.filter(u =>
u.name.toLowerCase().includes(searchQuery.toLowerCase())
);
});
// CORRETTO: $derived
const filteredUsersCorrect = $derived(
users.filter(u =>
u.name.toLowerCase().includes(searchQuery.toLowerCase())
)
);
</script>
$ effect 및 무한 루프
고전적인 실수와 편집 $effect $states 중 하나는 효과가
동일한 트랙이 무한 루프를 생성합니다.
// CICLO INFINITO: count tracciato, count modificato
$effect(() => {
console.log(count); // traccia count
count++; // modifica count -> ri-esegue l'effect
});
Svelte 5는 개발 중에 루프를 감지하고 오류를 발생시킵니다. $효과에서 $state를 수정해야 하는 경우,
사용하다 untrack() 추적하지 않고 읽거나 디자인을 다시 생각해보십시오.
$ effect.root 및 $ effect.pre
Svelte 5는 두 가지 특수 변형을 제공합니다. $effect:
<script lang="ts">
// $effect.pre: esegue PRIMA dell'aggiornamento del DOM
// Utile per leggere il DOM prima che venga modificato
// (es: salvare la posizione di scroll prima di un aggiornamento)
$effect.pre(() => {
const scrollPos = window.scrollY;
return () => {
// Ripristina scroll dopo l'aggiornamento del DOM
window.scrollTo(0, scrollPos);
};
});
// $effect.root: crea un effetto che non e legato al ciclo di vita
// del componente, utile fuori dai componenti
const cleanup = $effect.root(() => {
$effect(() => {
// Effect che persiste oltre la distruzione del componente
// (utile per singleton e stores globali)
});
return () => { /* cleanup manuale */ };
});
</script>
$ effect를 사용한 테스트 코드
테스트 구성요소 $effect 주의가 필요합니다. 효과가 예정되어 있습니다.
비동기식이므로 테스트는 업데이트 주기가 완료될 때까지 기다려야 합니다.
// test/MyComponent.test.ts
import { render } from '@testing-library/svelte';
import { tick } from 'svelte';
import MyComponent from './MyComponent.svelte';
test('$effect sincronizza con localStorage', async () => {
const { getByRole } = render(MyComponent);
const button = getByRole('button', { name: 'Toggle theme' });
button.click();
// Aspetta che il ciclo di aggiornamento Svelte completi
await tick();
expect(localStorage.getItem('theme')).toBe('dark');
});
결정: $효과 또는 $파생?
단순화된 의사결정 다이어그램:
- "기존 상태에서 값을 계산해야 하나요?" → 사용
$derived - “부작용이 있어도 수술을 해야 하나요?” → 사용
$effect - "DOM을 직접 업데이트해야 하나요?" → 사용
$effect(또는 오히려 액션 Svelte) - "상태가 변경되면 API 호출을 해야 합니까?" → 사용
$effect - “변환된 데이터를 UI에 표시해야 하나요?” → 사용
$derived
결론 및 다음 단계
$effect 강력하지만 전문적입니다. Svelte의 반응형 UI를
외부 세계 — DOM, 네트워크, 스토리지, 타사 라이브러리. 속하는 계산에 사용하십시오.
에 $derived 불필요한 복잡성과 잠재적인 버그가 발생합니다. 기억해야 할 패턴:
UI에 표시할 값을 생성하는 경우 e $derived; 그것이 무언가와 상호작용한다면
UI 외부, e $effect.
다음 기사의 주소 SvelteKit 자세히: 부하 작동 방식 서버 측 데이터 가져오기 기능, SSR 스트리밍이 TTFB를 줄이는 방법 및 형성 방법 작업은 클라이언트 측 JavaScript 없이 변형을 처리합니다.
시리즈: Svelte 5 및 프런트엔드 컴파일러 기반
- 기사 1: 컴파일러 기반 접근 방식 및 정신 모델
- 기사 2: $state 및 $derived — 룬과의 보편적인 반응성
- 제3조(본): $ effect 및 수명주기 — 사용 시기 (및 사용하지 않을 시기)
- 기사 4: SvelteKit SSR, 스트리밍 및 로드 기능
- 기사 5: Svelte 5의 전환 및 애니메이션
- 기사 6: Svelte의 접근성: 컴파일러 경고 및 모범 사례
- 7장: 전역 상태 관리: 컨텍스트, 룬 및 저장소
- 기사 8: Svelte 4에서 Svelte 5로 마이그레이션 — 실용 가이드
- 조항 9: Svelte 5: Vitest, 테스트 라이브러리 및 극작가에서의 테스트







