0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

最短で学ぶSvelte!チュートリアル要約&サンプルコード

Posted at

はじめに

Svelteに興味があるけれど、公式チュートリアルを一通り読むのは大変…と感じる方もいるかもしれません。
本記事では、Svelteの基本的な概念から応用的な使い方までを、実践的なサンプルコードとともに要約しました。

ショートハンド記法・リアクティブな変数・ストア・非同期処理・イベント管理・CSSバインディングなど、Svelteの主要な機能をできるだけ分かりやすくまとめています。

チュートリアルの補助的な資料として、学習の手助けになればと思っています。
これからSvelteを学ぶ方、すでに触れたことがある方の復習としても活用いただければ幸いです。

※当記事ではSvelte単体の解説記事になります。SvelteKitの内容は含まれてません

この記事で紹介する内容

機能 概要
ショートハンド記法 プロパティを簡潔に記述
動的HTML (@html) 文字列として渡されたHTMLをレンダリング
$derived 既存のデータを元に派生した値を計算
$inspect データの変更をリアルタイムで確認
keyed each 配列の要素削除時に連動させる
非同期処理 (await ブロック) 非同期データの取得と表示
イベントの親子順 (capture) 親が先にイベントを処理する
bind を活用したデータバインディング フォーム入力などの要素とデータを連携
CSSクラスの適用 クラスを条件付きで適用する方法
get / set クラスのカウンター管理
store 状態をコンポーネント間で共有
@snippet 再利用可能なスニペットを定義
svelte:boundary エラーハンドリングの実装

ショートハンド

Svelteでは、プロパティのショートハンド記法が使えます。
通常の記法と比較すると簡潔になります。
Playgroundはこちら

App.svelte
<script>
  let name = "Svelte";
</script>

<!-- 通常の記法 -->
<Component name={name} />

<!-- ショートハンド記法 -->
<Component {name} />
ChildComponent.svelte
<script>
  export let name;
</script>

<p>Hello, {name}!</p>

動的HTML

@htmlを使用すると、文字列として渡されたHTMLをレンダリングできます。

ユーザー入力を直接 @html に渡す場合、XSS(クロスサイトスクリプティング)の危険があるため、十分に検証してください。

App.svelte

<script>
  let htmlContent = "<strong>Dynamic HTML</strong>";
</script>

<p>{@html htmlContent}</p>

スクリーンショット 2025-03-13 13.58.02.png

$derived を使った派生状態の管理

Svelteの $derived を活用すると、他の変数の状態を元に派生値を計算できます。

Playgroundはこちら

App.svelte
<script>
	let numbers = $state([1, 2, 3, 4]);
	let total = $derived(numbers.reduce((t, n) => t + n, 0));

	// $derivedをつけないとtotalが10のまま
	// let total = numbers.reduce((t, n) => t + n, 0);

	function addNumber() {
		numbers.push(numbers.length + 1);
	}
</script>

<p>{numbers.join(' + ')} = {total}</p>

<button onclick={addNumber}>
	Add a number
</button>

$inspectで状態が変化する度にログを出す

開発時に変数の変化を監視するために $inspectを使用できます。
また、本番環境等ではログが出ないようになります。

Playgroundはこちら

App.svelte
<script>
  let count = $state(0);

  // `$inspect` を使って count の変更をリアルタイムで監視
  $inspect(count);

	// 初回の「0」のみ出力される
	console.log("console", count)

  function increment() {
    count += 1;
  }
</script>

<p>カウント: {count}</p>
<button onclick={increment}>+1</button>

keyed each で削除時に連動させる

リストをレンダリングする際に、各要素に一意のキーを持たせることで削除時の動作を適切に制御できます。
該当チュートリアル

App.svelte
<script>
	import Thing from './Thing.svelte';

	let things = $state([
		{ id: 1, name: 'apple' },
		{ id: 2, name: 'banana' },
		{ id: 3, name: 'carrot' },
		{ id: 4, name: 'doughnut' },
		{ id: 5, name: 'egg' }
	]);
</script>

<button onclick={() => things.shift()}>
	Remove first thing
</button>

<!-- {#each things as thing} にするとname の値が更新されるが、絵文字は更新されない -->
{#each things as thing (thing.id)}
	<Thing name={thing.name} />
{/each}
Thing.svelte
<script>
const emojis = {
    apple: '🍎',
    banana: '🍌',
    carrot: '🥕',
    doughnut: '🍩',
    egg: '🥚'
};

let { name } = $props();

const emoji = emojis[name];
</script>

<p>{emoji} = {name}</p>

非同期処理 (await ブロック)

await ブロックを使うと、非同期処理の状態に応じてUIを更新できます。
Playgroundはこちら

App.svelte
<script>
  async function fetchData() {
    return new Promise(resolve => {
      setTimeout(() => resolve("Loaded Data"), 2000);
    });
  }
</script>

<!-- 2秒後に"Loaded Data"と表示される -->
{#await fetchData()}
  <p>Loading...</p>
{:then data}
  <p>{data}</p>
{:catch error}
  <p>Error: {error}</p>
{/await}

capture でイベントの親子の順番を逆にする

通常、イベントは子要素から親要素へ伝播しますが、captureを使うと親要素が先にイベントを処理できます。
Playgroundはこちら

App.svelte
<script>
	// Parent → Childの順で発火する
  function handleParentClick() {
    alert("Parent clicked!");
  }
  function handleChildClick() {
    alert("Child clicked!");
  }
</script>

<div onclickcapture={handleParentClick}>
  Parent
  <button onclickcapture={handleChildClick}>Child</button>
</div>

bind を使用したデータバインディング

Svelteでは bind: を使うことで、フォームの入力値や要素のプロパティをリアクティブに連携できます。
Playgroundはこちら

App.svelte
<script>
  let name = "";
</script>

<!-- <input type="text" value={name}> にすると入力内容がDOMに反映されない -->
<input type="text" bind:value={name}>
<p>入力値: {name}</p>

CSSのクラスの付け方

Svelteでは class に配列を渡し、オブジェクト記法を用いることで条件付きクラスを適用できます。

Playgroundはこちら

App.svelte
<script>
  let isActive = false;
</script>

<button on:click={() => isActive = !isActive} class={["button", { "is-active": isActive }]}>
  Toggle Class
</button>

<style>
  .button {
    padding: 10px 20px;
    font-size: 16px;
    border: none;
    cursor: pointer;
    background-color: gray;
    color: white;
    transition: background-color 0.3s;
  }

  .is-active {
    background-color: blue;
    color: white;
  }
</style>

get / set

Svelteでは、クラスの プライベート変数 (#) を利用しつつ、get / set を活用することで、カウンターの状態管理を安全に行う ことができます。
Playgroundはこちら

App.svelte
<script>
  class Counter {
    #count = $state(0);

    constructor(initialValue = 0) {
      this.#count = initialValue;
    }

    // `get` でカウントを取得
    get count() {
      return this.#count;
    }

    // `set` でカウントを変更(0未満にはならないよう制御)
    set count(value) {
      if (value >= 0) {
        this.#count = value;
      } else {
        alert("カウントは0未満にはできません!");
      }
    }

    increment() {
      this.count = this.#count + 1;
    }

    decrement() {
      this.count = this.#count - 1;
    }
  }

  let counter = new Counter();
</script>

<p>カウント: {counter.count}</p>

<button onclick={() => counter.increment()}>+1</button>
<button onclick={() => counter.decrement()}>-1</button>

store

Svelteの store を活用すると、コンポーネント間での状態管理 が簡単にできます。
ここでは writable を使ってカウンターを作成し、リアクティブな更新されるようにします。
Playgroundはこちら

App.svelte
<script>
  import { writable } from 'svelte/store';

  // カウントのストアを作成(初期値 0)
  let count = writable(0);

  // カウンターを増減させる関数
  function increment() {
    count.update(n => n + 1);
  }

  function decrement() {
    count.update(n => (n > 0 ? n - 1 : 0)); // 0未満にならないよう制御
  }
</script>

<p>カウント: {$count}</p>

<!-- ストアの値を変更 -->
<button onclick={increment}>+1</button>
<button onclick={decrement}>-1</button>

@snippet

Svelteの @snippet は、コンポーネントの一部を再利用しやすくするための機能です。

基本の@snippetの使い方

Playgroundはこちら

App.svelte
<script>
  let message = "Hello, Svelte!";
</script>

<!-- Hello, Svelte! -->
{@render greetingSnippet()}

{#snippet greetingSnippet()}
	<p>{message}</p>
{/snippet}

@snippetにプロパティを渡す

特定の text を表示するボタンを @snippet にし、異なるボタンを作成できます。

Playgroundはこちら

App.svelte
<script>
  let message = "ボタンをクリックしてください!";

  function changeMessage(newMessage) {
    message = newMessage;
  }
</script>

<p>{message}</p>

<!-- スニペットのレンダリング -->
{@render customButton("Hello", () => changeMessage("こんにちは!"))}
{@render customButton("Goodbye", () => changeMessage("さようなら!"))}

{#snippet customButton(text, onClick)}
  <button onclick={onClick}>{text}</button>
{/snippet}

@snippetを使ったコンポーネントの分割

Svelteの@snippetを使って、コンポーネント間で動的なスニペットを受け渡し、状態を共有できます。
Playgroundはこちら

App.svelte

<script>
  import Children from "./Children.svelte";

  let message = "ボタンをクリックしてください!";

  function changeMessage(newMessage) {
    message = newMessage;
  }
</script>

<Children message={message} onChangeMessage={changeMessage}>
  {@render customButton(message, changeMessage)}
</Children>

{#snippet customButton(message, changeMessage)}
  <p>{message}</p>
  <button onclick={() => changeMessage("こんにちは、Svelte!")}>挨拶する</button>
  <button onclick={() => changeMessage("さようなら、Svelte!")}>別れる</button>
{/snippet}
Children.svelte
<script>
  let { children, message, onChangeMessage } = $props();
</script>

<div class="button-wrapper">
  {@render children(message, onChangeMessage)}
</div>

<style>
  .button-wrapper {
    display: flex;
    flex-direction: column;
    gap: 10px;
  }
</style>

svelte:boundaryを使ったエラーハンドリング

Playgroundはこちら

App.svelte
<script>
	import FlakyComponent from './FlakyComponent.svelte';
</script>

<svelte:boundary onerror={(e) => console.error(e)}>
	<FlakyComponent />

	{#snippet failed(error, reset)}
		<p>Oops! {error.message}</p>
		<button onclick={reset}>Reset</button>
	{/snippet}
</svelte:boundary>
FlakyComponent.svelte
<script>
	let mouse = $state({ x: 0, y: 0 });
</script>

<svelte:window
	onmousemove={(e) => {
		mouse.x = e.clientX;
		mouse.y = e.clientY;
	}}
/>

<p>{mouse.x}x{mouse.y}</p>

<button onclick={() => mouse = null}>
	押すとエラーが発生する
</button>

処理は下記の通りです

  • ボタンを押すと mouse = null になり、エラーが発生 → <svelte:boundary> が処理される
  • FlakyComponent.svelteでエラーが発生すると、onerror でログを出力し、failed snippet を表示
  • reset()を押すとエラーがリセットされる

スクリーンショット 2025-03-13 17.45.36.png

おわりに

本記事では、Svelteの公式チュートリアルを要約しながら、基本の主要な機能を解説しました。

機能 概要
ショートハンド記法 プロパティを簡潔に記述
動的HTML (@html) 文字列として渡されたHTMLをレンダリング
$derived 既存のデータを元に派生した値を計算
$inspect データの変更をリアルタイムで確認
keyed each 配列の要素削除時に連動させる
非同期処理 (await ブロック) 非同期データの取得と表示
イベントの親子順 (capture) 親が先にイベントを処理する
bind を活用したデータバインディング フォーム入力などの要素とデータを連携
CSSクラスの適用 クラスを条件付きで適用する方法
get / set クラスのカウンター管理
store 状態をコンポーネント間で共有
@snippet 再利用可能なスニペットを定義
svelte:boundary エラーハンドリングの実装

本記事がSvelteの学習や復習の助けになれば幸いです!
最後までお読みいただき、ありがとうございました!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?