13
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Ateam LifeDesignAdvent Calendar 2023

Day 2

Svelte5のalpha版がリリースされたので新機能を紹介します!

Last updated at Posted at 2023-12-01

はじめに

2023/11/11に開催されたSvelte Summit Fall 2023でSvelte5のalpha版がリリースされました:tada:
この記事ではどういう機能が追加されたのか、どういう書き方に変わるかを紹介します。
現在Svelte5に向けて精力的に開発が進められていて日々新機能が追加されてます。
この記事はすぐに情報が古くなったりする可能性がありますので注意してください。
記事執筆時点のバージョンはsvelte@5.0.0-next.16です。

Runes

Runes は Svelte コンパイラに働きかけるシンボルです。現在の Svelte では let=exportキーワード、そして $: ラベル を特殊なものとして意味するように使用するのに対し、Rune は同様のことを 関数の構文(function syntax) で実現します。

引用:https://svelte.jp/blog/runes#what-are-runes

$state

リアクティブなステートを宣言するには、$stateを使用します。
書くことが増えて複雑になったと思うかもしれないですが、アプリケーションが複雑になってくるにつれ、どの値がリアクティブでどの値がリアクティブでないのか判別するのが難しくなってきますし、コードの振る舞いが.svelte.jsで変わってくるとリファクタリングが難しくなる等の理由でこういった変更がされたようです。

Svelte4

デモ

<script>
  let name = "John";
</script>

<h1>Hello {name}</h1>

Svelte5

デモ

<script>
  let name = $state("John");
</script>

<h1>Hello {name}</h1>

$derived

$:の代わりとして使用することができます。
従来、$: はトップレベルでのみ使用可能であり、.svelteファイル内でしか機能しなかったため、リファクタリングが困難でした。これらの点が改善されたため、より使いやすくなりました。

デモ

Svelte4

<script>
  let count = 10;
  $: doubleCount = count * 2;
</script>

<div>{doubleCount}</div>

デモ

Svelte5

<script>
  let count = $state(10);
  const doubleCount = $derived(count * 2);
</script>

<div>{doubleCount}</div>

$effect

onMountの代わりとして使用することができます。
特定の値が変更されたときや、コンポーネントがDOMにマウントされたときにコードを実行する必要がある場合に使用します。

Svelte4

デモ

<script>
  import { onMount } from "svelte";

  let pageTitle = "";

  onMount(() => {
    pageTitle = document.title;
  });
</script>

<svelte:head>
	<title>Svelte4</title>
</svelte:head>

<p>Page title is: {pageTitle}</p>

Svelte5

デモ

<script>
  let pageTitle = $state("");

  $effect(() => {
    pageTitle = document.title;
  });
</script>

<svelte:head>
	<title>Svelte5</title>
</svelte:head>

<p>Page title is: {pageTitle}</p>

$effect.pre

beforeUpdateの代わりとして使用することができます。
DOMが更新される前にコードを実行する必要がある場合に使用します。

Svelte4

デモ

<script>
  import { beforeUpdate } from "svelte";
	
  beforeUpdate(() => {
  	console.log("beforeUpdate");
  });
</script>

Svelte5

デモ

<script>
  $effect.pre(() => {
  	console.log("beforeUpdate");
  });
</script>

$effect.active

Svelte5で追加された機能です。
コードがエフェクト内で実行されているのか、テンプレート内で実行されているのかを示す機能です。

デモ

<script>
  console.log('in component setup:', $effect.active()); // false

  $effect(() => {
	 console.log('in effect:', $effect.active()); // true
  });
</script>

<p>in template: {$effect.active()}</p> <!-- true -->

$effect.root

Svelte5で追加された機能です。
自動クリーンアップを行わない非追跡スコープを作成する機能です。これは、手動で制御したいネストされたエフェクトに便利です。このRuneは、コンポーネントの初期化フェーズの外側でエフェクトを作成することもできます。

デモ

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

	const cleanup = $effect.root(() => {
		$effect(() => {
			console.log(count);
		});

		return () => {
			console.log('effect root cleanup');
		};
	});
</script>

$props

export letの代わりとして使用することができます。
通常のjsとは異なる振る舞いとして使用されていたので違和感を持たれる方もいたと思いますが、その点が改善されました。
また、$$props$$restPropsといった機能の代わりにもなります。

Svelte4

デモ

<script>
	export let optionalProp = 42;
	export let requiredProp;
</script>

<p>optionalProp:{optionalProp}</p>
<p>requiredProp:{requiredProp}</p>

Svelte5

デモ

<script>
	let { optionalProp = 42, requiredProp } = $props();
</script>

<p>optionalProp:{optionalProp}</p>
<p>requiredProp:{requiredProp}</p>

$inspect

Svelte5で追加された機能です。
console.logとほぼ同じですが、渡される引数が変更されると再び実行される、という特徴があります。$inspectは、リアクティブなデータの変化を詳しく監視します。つまり、オブジェクトや配列の内部のデータにリアクティブな性質を持たせておき、そこでデータが更新された場合、その関数が再び実行されます。

デモ

<script>
	let count = $state(0);
	let message = $state('hello');

	$inspect({ count, message });
</script>

<button onclick={() => count++}>Increment</button>
<input bind:value={message} />

Snippets

slotの代わりとして使用することができます。
#snippet@renderを使うことでコンポーネント内でマークアップを再利用することができます。

以下のような重複したコードを記述する代わりに...

デモ

{#each images as image}
	{#if image.href}
		<a href={image.href}>
			<figure>
				<img
					src={image.src}
					alt={image.caption}
					width={image.width}
					height={image.height}
				/>
				<figcaption>{image.caption}</figcaption>
			</figure>
		</a>
	{:else}
		<figure>
			<img
				src={image.src}
				alt={image.caption}
				width={image.width}
				height={image.height}
			/>
			<figcaption>{image.caption}</figcaption>
		</figure>
	{/if}
{/each}

#snippet@renderを使ってこのように書けます。

デモ

{#snippet figure(image)}
	<figure>
		<img
			src={image.src}
			alt={image.caption}
			width={image.width}
			height={image.height}
		/>
		<figcaption>{image.caption}</figcaption>
	</figure>
{/snippet}

{#each images as image}
	{#if image.href}
		<a href={image.href}>
			{@render figure(image)}
		</a>
	{:else}
		{@render figure(image)}
	{/if}
{/each}

Event handlers

Svelte4ではon:ディレクティブを使用してイベントリスナーを要素にアタッチしていましたが、Svelte5では他のプロパティと同じようにイベントハンドラを使用します。

<script>
	let count = $state(0);
</script>
- <button on:click={() => count++}>
+ <button onclick={() => count++}>
	clicks: {count}
</button>

さいごに

Svelte5どうでしょうか?
今までSvelteを書いてきた人は少し複雑になったと感じた人もいるかもしれません。
私は業務でSvelteを書いているので実践的なコードを書く経験があるんですが、実践的なコードを書くとどうしても複雑なことをやらないといけないことがあります。そういった場合に今回のSvelte5の変更によってコードが読みやすくなったと感じますし、よりJavaScriptの基本に近くなったり、使いにくかった機能がなくなったりして、学習コストは少なくなったのかなと個人的には思っています。
リリースが楽しみです!

お知らせ

2023/12/8 19:00~ Svelte Japan Online Meetup #1が開催されます!
当日はYouTubeで配信する予定になっていて気軽にご覧いただけますので是非参加してください。

13
3
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
13
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?