이벤트 핸들링 — on: 디렉티브에서 콜백 Props까지
Svelte 5에서는
on:click이 사라지고onclick으로 바뀌었습니다 — HTML 표준에 더 가까워졌다는 뜻입니다.
개념 정의
Svelte에서 이벤트 핸들링은 DOM 요소에 이벤트 리스너를 연결하는 것입니다. Svelte 5에서는 기존의 on: 디렉티브 대신 표준 HTML 이벤트 속성 방식(onclick, oninput 등)을 사용합니다.
DOM 이벤트 기본
<script>
let count = $state(0);
function handleClick() {
count++;
}
</script>
<!-- 함수 참조 -->
<button onclick={handleClick}>클릭: {count}</button>
<!-- 인라인 함수 -->
<button onclick={() => count++}>클릭: {count}</button>
<!-- 이벤트 객체 사용 -->
<button onclick={(e) => {
console.log('클릭 위치:', e.clientX, e.clientY);
count++;
}}>
클릭: {count}
</button>
자주 쓰는 이벤트
<script>
let text = $state('');
let isHovered = $state(false);
let position = $state({ x: 0, y: 0 });
</script>
<!-- 입력 이벤트 -->
<input
oninput={(e) => text = e.target.value}
placeholder="입력하세요"
/>
<!-- 키보드 이벤트 -->
<input
onkeydown={(e) => {
if (e.key === 'Enter') {
console.log('엔터 입력:', text);
}
}}
/>
<!-- 마우스 이벤트 -->
<div
onmouseenter={() => isHovered = true}
onmouseleave={() => isHovered = false}
onmousemove={(e) => position = { x: e.clientX, y: e.clientY }}
class:hovered={isHovered}
>
{isHovered ? '마우스 올림!' : '마우스를 올려보세요'}
</div>
<!-- 폼 제출 -->
<form onsubmit={(e) => {
e.preventDefault();
console.log('제출:', text);
}}>
<input bind:value={text} />
<button type="submit">제출</button>
</form>
<style>
.hovered { background: #f0f0f0; }
</style>
이벤트 수정자
Svelte 5에서는 on:click|preventDefault 같은 수정자 문법이 사라졌습니다. 대신 이벤트 핸들러 안에서 직접 처리합니다.
<script>
function handleSubmit(e) {
e.preventDefault();
console.log('폼 제출 방지됨');
}
function handleInnerClick(e) {
e.stopPropagation();
console.log('내부 클릭 — 버블링 중단');
}
</script>
<form onsubmit={handleSubmit}>
<button type="submit">제출</button>
</form>
<div onclick={() => console.log('외부')}>
<button onclick={handleInnerClick}>내부</button>
</div>
유틸 함수로 수정자 구현
<script>
// 재사용 가능한 이벤트 수정자 유틸
function preventDefault(fn) {
return (e) => {
e.preventDefault();
fn(e);
};
}
function handleSubmit(e) {
console.log('제출!');
}
</script>
<form onsubmit={preventDefault(handleSubmit)}>
<button type="submit">제출</button>
</form>
컴포넌트 이벤트 — 콜백 Props
Svelte 5에서는 createEventDispatcher 대신 ** 콜백 props** 패턴을 사용합니다.
<!-- Button.svelte -->
<script>
let { onclick, label } = $props();
</script>
<button {onclick}>{label}</button>
<!-- App.svelte -->
<script>
import Button from './Button.svelte';
function handleClick() {
console.log('버튼 클릭됨!');
}
</script>
<Button onclick={handleClick} label="클릭하세요" />
커스텀 데이터 전달
<!-- TodoItem.svelte -->
<script>
let { todo, onDelete, onToggle } = $props();
</script>
<div class="todo">
<input
type="checkbox"
checked={todo.done}
onchange={() => onToggle(todo.id)}
/>
<span class:done={todo.done}>{todo.text}</span>
<button onclick={() => onDelete(todo.id)}>삭제</button>
</div>
<style>
.done { text-decoration: line-through; }
</style>
<!-- TodoList.svelte -->
<script>
import TodoItem from './TodoItem.svelte';
let todos = $state([
{ id: 1, text: '공부하기', done: false },
{ id: 2, text: '운동하기', done: true },
]);
function deleteTodo(id) {
todos = todos.filter(t => t.id !== id);
}
function toggleTodo(id) {
const todo = todos.find(t => t.id === id);
if (todo) todo.done = !todo.done;
}
</script>
{#each todos as todo (todo.id)}
<TodoItem {todo} onDelete={deleteTodo} onToggle={toggleTodo} />
{/each}
이벤트 위임
<script>
let items = $state(['사과', '바나나', '딸기', '포도', '수박']);
function handleClick(e) {
const index = e.target.dataset.index;
if (index !== undefined) {
console.log(`${items[index]} 클릭됨`);
}
}
</script>
<ul onclick={handleClick}>
{#each items as item, i}
<li data-index={i}>{item}</li>
{/each}
</ul>
면접 포인트
- "Svelte 5에서 이벤트 처리가 어떻게 바뀌었나요?":
on:디렉티브가 사라지고 표준 HTML 이벤트 속성(onclick등)을 사용합니다. 컴포넌트 이벤트도createEventDispatcher대신 콜백 props 패턴으로 전환되었습니다. - "이벤트 수정자가 없어진 이유는?": HTML 표준에 가까운 API를 지향하면서 Svelte 전용 문법을 줄였습니다.
e.preventDefault()를 직접 호출하는 것이 더 명시적이고 표준에 부합합니다.
정리
Svelte 5의 이벤트 핸들링은 "특별한 문법 없이, 표준 HTML/JavaScript와 동일하게"를 지향합니다. on:click 대신 onclick, dispatch 대신 콜백 props — JavaScript를 잘 알면 Svelte도 잘 쓸 수 있다는 설계 철학이 드러납니다.
댓글 로딩 중...