Special elements

svelte:self

Svelte는 여러 빌트인 요소들을 제공한다. 먼저, <svelte:self>는 컴포넌트를 재귀적으로 활용할 수 있게 해준다. 기본적으로 모듈은 스스로를 import 하는 것이 불가능하기 때문에, <svelte:self>가 필요하다.

이는 폴더 안에 다른 폴더가 포함될 수 있는 폴더 트리 뷰와 같은 것들을 구성할 때 유용하다.

{#if file.type === 'folder'}
	<svelte:self {...file}/>
{:else}
	<File {...file}/>
{/if}

svelte:component

<svelte:component>는 동적으로 특정 컴포넌트가 해당 요소의 위치가 올 수 있을 경우에 활용할 수 있다.

이를테면, 아래처럼 조건부로 컴포넌트를 렌더링하고자 할 때, <svelte:component>를 통해 하나의 동적 컴포넌트로 처리해줄 수 있다.

{#if selected.color === 'red'}
	<RedThing/>
{:else if selected.color === 'green'}
	<GreenThing/>
{:else if selected.color === 'blue'}
	<BlueThing/>
{/if}

위의 코드는 아래의 한줄로 대체될 수 있다.

<svelte:component this={selected.component}/>

svelte:window

바닐라 JS 상에서 어떤 DOM 요소에든 이벤트 리스너를 추가할 수 있듯, Svelte에서 window 오브젝트에 이벤트 리스너를 추가하고자 한다면 <svelte:window>를 이용하면 된다.

<svelte:window on:keydown={handleKeydown}/>

svelte:window bindings

window의 특정 프로퍼티에 바인딩을 해줄 수도 있다.

<svelte:window bind:scrollY={y}/>

아래는 바인딩 가능한 프로퍼티의 리스트다.

  • innerWidth
  • innerHeight
  • outerWidth
  • outerHeight
  • scrollX
  • scrollY
  • online - window.navigator.onLine과 동일

scrollXscrollY을 제외한 모두는 읽기 전용 프로퍼티다.

svelte:body

<svelte:window>와 비슷하게, <svelte:body> 요소 역시 document.body에 직접적으로 이벤트 리스너를 추가해야 하는 경우에 사용할 수 있다.

window에서는 발생하지 않는 mouseenter 혹은 mouseleave 이벤트를 사용해야 하는 경우에 유용하다.

<svelte:body
	on:mouseenter={handleMouseenter}
	on:mouseleave={handleMouseleave}
/>

svelte:head

<svelte:head> 요소는 문서의 <head> 내에 요소를 추가해야할 때 사용할 수 있다.

<svelte:head>
	<link rel="stylesheet" href="tutorial/dark-theme.css">
</svelte:head>

SSR 모드의 경우, <svelte:head>의 내용은 HTML의 나머지와 별도로 반환된다.

svelte:options

<svelte:options>는 컴파일링 옵션을 설정할 수 있게 해준다.

예를 들어, 해당 컴포넌트에서 설정할 수 있는 immutable 옵션이 존재하는데, 이는 해당 컴포넌트가 immutable 데이터를 기반으로 동작함을 의미한다.

이를테면, 아래와 같이 Todo 컴포넌트가 존재한다고 하자.

<script>
	import { afterUpdate } from 'svelte';
	import flash from './flash.js';

	export let todo;

	let div;

	afterUpdate(() => {
    // 아래의 flash는 애니메이션 효과.
		flash(div);
	});
</script>

<!-- the text will flash red whenever
     the `todo` object changes -->
<div bind:this={div} on:click>
	{todo.done ? '👍': ''} {todo.text}
</div>

<style>
	div {
		cursor: pointer;
		line-height: 1.5;
	}
</style>

헌데, 아래처럼 여러 개의 Todo를 갖는 리스트를 구현하려고 하는 상황을 생각해보자.

toggle이 실행될 때, map 메서드에 의해서 새로운 todos가 반환되며, 이에 따라 하위의 일부 Todo에 대해서는 결론적으로는 변경된 데이터가 없어 굳이 새로 리렌더링할 필요가 없음에도 모든 Todo 컴포넌트가 리렌더링 과정을 거치게 된다.

let todos = [
  { id: 1, done: true, text: 'wash the car' },
  { id: 2, done: false, text: 'take the dog for a walk' },
  { id: 3, done: false, text: 'mow the lawn' },
];

function toggle(toggled) {
  todos = todos.map((todo) => {
    if (todo === toggled) {
      // return a new object
      return {
        id: todo.id,
        text: todo.text,
        done: !todo.done,
      };
    }

    // return the same object
    return todo;
  });
}

이러한 상황을 방지하기 위해서, immutable 옵션을 통해 props 값의 참조가 유지된다면 리렌더링을 수행하지 않도록 한다.

// <svelte:options immutable/>을 써도 된다.

<svelte:options immutable={true}/>

아래는 <svelte:options>에서 설정할 수 있는 옵션들이다.

  • immutable={true} - mutable 데이터를 사용하지 않겠다는 뜻으로, 컴포넌트는 값의 변경 여부를 확인하기 위해 단순 참조 비교(simple referential quality check)를 거친다.
  • immutable={false} - 기본값. 값이 변경되었는지의 여부에 대해 더 엄격하게 체크한다.
  • accessors={true} - 컴포넌트의 props에 대한 getter와 setter를 추가한다.
  • accessors={false} - 기본값.
  • namespace="..." - 컴포넌트가 사용될 네임스페이스. 일반적으로 svg에서 사용된다.
  • tag="..." - 컴포넌트를 커스텀 요소로 컴파일링할 때 사용할 이름.

svelte:fragment

<svelte:fragment> 요소는 named slot에 요소를 전달하고자 할 때, 굳이 별도의 컨테이너(ex. div)를 통해 요소를 묶어주지 않아도 곧바로 전달할 수 있게끔 해준다. React에서의 Fragment와 동일하다.(<></>)

<svelte:fragment slot="footer">
	<p>All rights reserved.</p>
	<p>Copyright (c) 2019 Svelte Industries</p>
</svelte:fragment>