dev-guide

Svelte 5 Runes 완벽 가이드 — 새로운 반응형 시스템으로의 전환

Svelte 5에서 도입된 Runes($state, $derived, $effect, $props)의 개념, 기존 Svelte 4와의 차이점, 마이그레이션 전략을 실무 예제와 함께 정리하였다.

★★★★★적극 추천
SvelteSvelte5Runes프론트엔드반응형
Svelte 5 Runes 완벽 가이드 — 새로운 반응형 시스템으로의 전환
  • ·Svelte 5 릴리스: 2024년 10월
  • ·$state, $derived, $effect, $props 네 가지 핵심 Rune 도입
  • ·컴파일러 기반 반응형 시스템을 Signal 기반으로 전환
  • ·Svelte 4와 하위 호환성 유지 — 점진적 마이그레이션 가능
Svelte 4 기반 대시보드를 Svelte 5로 마이그레이션하면서 기존의 $: 반응형 선언을 $derived와 $effect로 전환하였다. 처음에는 문법 변화에 적응하는 데 시간이 걸렸지만, 의존성이 명시적으로 드러나면서 디버깅이 훨씬 수월해졌다. 특히 복잡한 상태 계산 로직에서 순환 의존성 문제가 사라진 점이 인상적이었다.

Runes란 무엇인가

Svelte 5 Runes와 Svelte 4 반응형의 차이

Svelte 4에서는 컴파일러가 let 선언 변수의 재할당을 자동으로 감지하여 DOM을 업데이트하는 암묵적 반응형 방식을 사용하였다. 이 방식은 단순하지만, 컴포넌트 외부에서 반응형 상태를 정의하거나 클래스 내에서 사용하기 어려웠고, 반응형 변수와 일반 변수를 구분하는 명시적인 방법이 없었다. Svelte 5의 Runes는 $state(), $derived() 같은 명시적 선언으로 반응형 의도를 코드에서 직접 표현하며, 컴파일러에 의존하지 않고 JavaScript Signal 기반으로 동작하여 컴포넌트 외부에서도 반응형 상태를 자유롭게 사용할 수 있다.

<!-- Svelte 4 방식 -->
<script>
  let count = 0               // 재할당 감지로 반응형
  $: doubled = count * 2      // 반응형 선언문
</script>

<!-- Svelte 5 Runes 방식 -->
<script>
  let count = $state(0)          // 명시적 반응형 상태
  let doubled = $derived(count * 2)  // 파생 값

  function increment() { count++ }
</script>
<button onclick={increment}>{count} (doubled: {doubled})</button>

Svelte 5 Runes $state와 $derived 핵심 패턴

$state(initialValue)는 반응형 상태를 선언하며, 값을 변경하면 의존하는 모든 UI가 자동으로 업데이트된다. 객체나 배열을 $state로 선언하면 내부 프로퍼티 변경도 깊이 추적되어 state.user.name = "새이름" 같은 뮤테이션도 반응형으로 처리된다. $derived(expression)는 다른 반응형 값에서 계산되는 읽기 전용 값을 선언하며, 의존하는 상태가 변경될 때만 재계산된다. $derived.by(() => { ... })를 사용하면 복잡한 계산 로직을 블록으로 표현할 수 있다.

$effect와 $props 활용

Svelte 5 Runes $effect로 사이드 이펙트 관리

$effect(() => { ... })는 내부에서 읽은 반응형 상태가 변경될 때마다 자동으로 실행되는 사이드 이펙트를 선언한다. React의 useEffect와 달리 의존성 배열을 명시할 필요 없이 실제 사용하는 상태를 자동으로 추적한다. 클린업 함수는 이펙트에서 함수를 반환하면 되며, 다음 이펙트 실행 전이나 컴포넌트 언마운트 시 자동 호출된다. $effect.pre는 DOM 업데이트 전에 실행되어 레이아웃 측정 같은 작업에 사용할 수 있다.

Svelte 5 Runes $props로 컴포넌트 인터페이스 정의

const { name, age = 0, ...rest } = $props()는 컴포넌트의 props를 구조 분해로 선언하며, 기본값과 나머지 props를 자연스럽게 표현할 수 있다. TypeScript와 함께 사용할 때는 $props<{ name: string; age?: number }>()로 타입을 명시한다. Svelte 4의 export let 방식보다 의도가 명확하고, 나머지 props를 자식 요소에 스프레드하는 패턴도 깔끔하게 표현된다. props의 양방향 바인딩이 필요할 때는 $bindable() Rune을 사용한다.

Svelte 4에서 5로 마이그레이션

Svelte 5로의 점진적 마이그레이션 전략

Svelte 5는 기존 Svelte 4 문법과 하위 호환되므로 프로젝트 전체를 한 번에 전환할 필요 없다. 기존 컴포넌트는 그대로 두고, 새로 작성하는 컴포넌트부터 Runes를 사용하는 혼합 방식이 권장된다. Svelte 팀이 제공하는 svelte-migrate CLI 도구로 컴포넌트 단위로 자동 변환이 가능하며, 변환 결과를 검토하고 테스트하면서 점진적으로 마이그레이션할 수 있다.

Svelte 5와 SvelteKit 통합 방법

SvelteKit 2.x는 Svelte 5를 기본으로 지원한다. 서버 로드 함수에서 반환한 데이터는 페이지 컴포넌트에서 $props()로 접근하며, $derived와 조합하면 서버 데이터 기반의 클라이언트 상태를 간결하게 관리할 수 있다. Form actions와 Svelte 5의 이벤트 처리가 통합되어 Server Actions 없이도 풀스택 폼 처리가 가능하다.

자주 묻는 질문

Svelte 4 코드를 Svelte 5로 마이그레이션하면 호환성 문제가 생기나요?+

Svelte 5는 4와 하위 호환되어 기존 문법이 그대로 동작합니다. 다만 일부 deprecated API가 있으며 svelte-migrate 도구로 자동 변환을 지원합니다.

Svelte 5 Runes는 React Hooks와 어떻게 다른가요?+

Runes는 컴파일러가 처리하여 규칙 제약이 없고 반응형 추적이 자동입니다. React Hooks는 런타임 기반이며 의존성 배열 관리가 필요합니다. Runes의 학습 곡선이 더 낮습니다.

관련 글