본문 바로가기
개발

[Svelte] svelte5 새로운 문법의 도입

by 쥰5017 2025. 12. 24.

Svelte 5의 새로운 문법

Svelte 5가 2024년에 정식 출시되면서 기존 문법과 많은 부분이 달라졌다. 특히 반응성 시스템이 완전히 새로워졌는데, 이제 $state, $derived, $effect 같은 rune이라는 개념을 사용한다.

 

1. $state - 상태 관리의 새로운 방식

기존 Svelte에서는 그냥 let count = 0 이렇게 선언하면 반응성이 자동으로 작동했다. 하지만 Svelte 5에서는 명시적으로 $state()를 사용해야 한다. (스벨트5에서도 여전히 스벨트4 문법을 지원하지만 가독성을 위해)

<script>
  let count = $state(0);
  let user = $state({ name: '김철수', age: 30 });
  
  function increment() {
    count++;
  }
</script>

<button onclick={increment}>클릭: {count}</button>
<p>{user.name}님의 나이는 {user.age}세</p>

$state()로 선언한 변수는 값이 변경되면 자동으로 UI가 업데이트된다. 객체나 배열도 깊은 반응성을 지원하기 때문에 중첩된 속성을 변경해도 감지된다.

 

2. $derived - 계산된 값

다른 상태에 의존하는 값을 만들 때 $derived()를 사용한다. Vue의 computed나 비슷한 개념이다.

<script>
  let firstName = $state('홍');
  let lastName = $state('길동');
  let fullName = $derived(`${firstName}${lastName}`);
  
  let numbers = $state([1, 2, 3, 4, 5]);
  let sum = $derived(numbers.reduce((a, b) => a + b, 0));
</script>

<p>전체 이름: {fullName}</p>
<p>합계: {sum}</p>

$derived()는 내부에서 사용하는 $state 값이 변경될 때마다 자동으로 재계산된다. 따로 의존성을 명시할 필요가 없다.

 

3. $effect - 부수 효과 처리

컴포넌트가 마운트되거나 상태가 변경될 때 특정 코드를 실행하려면 $effect()를 사용한다.

<script>
  let count = $state(0);
  
  $effect(() => {
    console.log(`카운트가 ${count}로 변경됨`);
    document.title = `카운트: ${count}`;
  });
  
  $effect(() => {
    const interval = setInterval(() => {
      count++;
    }, 1000);
    
    return () => {
      clearInterval(interval);
    };
  });
</script>

$effect() 내부에서 사용된 $state 값이 변경되면 자동으로 다시 실행된다. 함수를 반환하면 cleanup 로직으로 사용되는데, 컴포넌트가 언마운트되거나 effect가 재실행되기 전에 호출된다.

 

4. $props - Props 받기

부모 컴포넌트로부터 데이터를 받을 때는 $props()를 사용한다.

<script>
  let { title, count = 0, onClick } = $props();
</script>

<div>
  <h2>{title}</h2>
  <button onclick={onClick}>카운트: {count}</button>
</div>

구조 분해 할당으로 props를 받고, 기본값도 설정할 수 있다. TypeScript를 사용한다면 타입도 지정 가능하다.

 

5. 이벤트 핸들링

Svelte 5에서는 on:click 대신 표준 HTML 속성인 onclick을 사용한다.

<script>
  let message = $state('');
  
  function handleClick(event) {
    message = '버튼이 클릭됨';
  }
  
  function handleInput(event) {
    message = event.target.value;
  }
</script>

<button onclick={handleClick}>클릭</button>
<input oninput={handleInput} value={message} />
<p>{message}</p>

이벤트 수식어도 달라졌다. |preventDefault|stopPropagation 같은 방식이 아니라 함수 내부에서 직접 처리해야 한다.

 

6. 조건부 렌더링과 반복

조건부 렌더링과 리스트 렌더링은 기존과 비슷하지만, key 지정 방식이 약간 다르다.

<script>
  let isLoggedIn = $state(false);
  let todos = $state([
    { id: 1, text: 'Svelte 5 공부하기' },
    { id: 2, text: '프로젝트 만들기' }
  ]);
</script>

{#if isLoggedIn}
  <p>환영합니다!</p>
{:else}
  <p>로그인이 필요합니다.</p>
{/if}

<ul>
  {#each todos as todo (todo.id)}
    <li>{todo.text}</li>
  {/each}
</ul>

#each 블록에서 괄호 안에 key를 지정하는 방식은 동일하다.

 

7. 양방향 바인딩

bind: 디렉티브는 Svelte 5에서도 그대로 사용된다.

<script>
  let text = $state('');
  let checked = $state(false);
  let selected = $state('option1');
</script>

<input bind:value={text} />
<p>입력값: {text}</p>

<input type="checkbox" bind:checked={checked} />
<p>체크 상태: {checked}</p>

<select bind:value={selected}>
  <option value="option1">옵션 1</option>
  <option value="option2">옵션 2</option>
</select>

 

 

 

Svelte 5의 rune 시스템은 처음에는 낯설 수 있지만, 반응성이 어떻게 작동하는지 명확하게 보여준다는 장점이 있다. 특히 복잡한 상태 관리나 부수 효과를 다룰 때 예측 가능한 동작을 보장한다. 기존 Svelte 3/4 문법과는 많이 다르지만, 더 명확하고 강력한 도구가 된 것은 확실하다.

 

반응형

댓글