Svelte5ではcreateEventDispatcher関数が非推奨になりました

# createEventDispatcherとは
`createEventDispatcher`は、Svelteコンポーネントからカスタムイベントをディスパッチ（発行）するための関数です。これを使うことで、子コンポーネントが親コンポーネントにデータやイベントを通知することができます。

# Svelte5でどう変わったのか

Svelte5では、`createEventDispatcher`関数が非推奨となり、代わりに`Props`としてコールバック関数を渡すようになりました。

また、 `on:`ディレクティブが非推奨になっていますので`on:click`は`onclick`のように単なるプロパティとしてイベントハンドラを指定するようになりました。

例をいくつか紹介します。

[Docs](https://svelte.dev/docs/svelte/svelte#createEventDispatcher)

## 例1

### Svelte4以前の書き方

[Demo]https://svelte.dev/playground/9553ad5a88c046c2a1d009e05894032c?version=4.2.19)

```svelte:子コンポーネント
<script>
 import { createEventDispatcher } from 'svelte';
 
 const dispatch = createEventDispatcher();
</script>

<button on:click={() => dispatch('notify', 'detail value')}>Fire Event</button>
```

```svelte:親コンポーネント
<script>
  import Child from './Child.svelte';

  function callbackFunction(event) {
    console.log(`Notify fired! Detail: ${event.detail}`);
  }
</script>

<Child on:notify={callbackFunction} />
```

### Svelte5で変わった書き方

[Demo](https://svelte.dev/playground/6949c03e71e54b2eb400fc3e2e7a034f?version=5.10.1)

```svelte:子コンポーネント
<script>
  let { onNotify } = $props();
</script>

<button onclick={() => onNotify('detail value')}>Fire Event</button>
```

```svelte:親コンポーネント
<script>
  import Child from './Child.svelte';

  function handleNotify(detail) {
    console.log(`Notify fired! Detail: ${detail}`);
  }
</script>

<Child onNotify={handleNotify} />
```

## 例2

### Svelte4以前の書き方

[Demo](https://svelte.dev/playground/341a7801188d49f9a715f194fae68620?version=4.2.19)

```svelte:子コンポーネント
<script>
  import { createEventDispatcher } from 'svelte';
  const dispatch = createEventDispatcher();

  function handleAdd() {
    dispatch('add');
  }

  function handleSubtract() {
    dispatch('subtract');
  }
</script>

<button on:click={handleAdd}>Add</button>
<button on:click={handleSubtract}>Subtract</button>
```

```svelte:親コンポーネント
<script>
  import Child from './Child.svelte';
  let number = 0;

  function handleAdd() {
    number++;
  }
  
  function handleSubtract() {
    number--;
  }
</script>

<Child on:add={handleAdd} on:subtract={handleSubtract} />

<p>Number: {number}</p>
```

### Svelte5で変わった書き方

[Demo](https://svelte.dev/playground/2415a1b3b4534297a502c42f3583354c?version=5.10.1)

```svelte:子コンポーネント
<script>
  let { add, subtract } = $props();
</script>

<button onclick={add}>Add</button>
<button onclick={subtract}>Subtract</button>
```

```svelte:親コンポーネント
<script>
  import Child from "./Child.svelte"

  let number = $state(0);
</script>

<Child add={() => number++} subtract={() => number--} />

<p>Number: {number}</p>
```

## 例3

### Svelte4以前の書き方

[Demo](https://svelte.dev/playground/aa1ef4e6e73f4ee4903befd0d9a1b42e?version=4.2.19)

```svelte:子コンポーネント
<script>
	import { createEventDispatcher } from 'svelte';
 
	const dispatch = createEventDispatcher();
 
	let power = 5;
</script>

<button on:click={() => dispatch('inflate', power)}>
	inflate
</button>

<button on:click={() => dispatch('deflate', power)}>
	deflate
</button>

<button on:click={() => power--}>-</button>

Pump power: {power}

<button on:click={() => power++}>+</button>
```

```svelte:親コンポーネント
<script>
	import Child from './Child.svelte';

	let size = 15;
	let burst = false;

	function reset() {
		size = 15;
		burst = false;
	}
</script>

<Child
	on:inflate={(power) => {
		size += power.detail;
		if (size > 75) burst = true;
	}}
	on:deflate={(power) => {
		if (size > 0) size -= power.detail;
	}}
/>

{#if burst}
	<button on:click={reset}>new balloon</button>
	<span class="boom">💥</span>
{:else}
	<span class="balloon" style="scale: {0.01 * size}">
		🎈
	</span>
{/if}

<style>
	span {
		position: fixed;
		left: 0;
		top: 0;
		width: 100%;
		height: 100%;
		font-size: 100vh;
		text-align: center;
		line-height: 1;
		pointer-events: none;
	}

	.balloon {
		transition: scale 0.2s;
	}

	.boom {
		animation: boom 0.5s forwards;
	}

	@keyframes boom {
		0% {scale: 0.6}
		25% {scale: 0.75}
		100% {scale: 0}
	}
</style>
```

### Svelte5で変わった書き方

[Demo](https://svelte.dev/playground/35615b5dd2ff4085b9729882452489ea?version=5.10.1)

```svelte:子コンポーネント
<script>
	let { inflate, deflate } = $props();
	
	let power = $state(5);
</script>

<button onclick={() => inflate(power)}>
	inflate
</button>

<button onclick={() => deflate(power)}>
	deflate
</button>

<button onclick={() => power--}>-</button>

Pump power: {power}

<button onclick={() => power++}>+</button>
```

```svelte:親コンポーネント
<script>
	import Child from './Child.svelte';

	let size = $state(15);
	let burst = $state(false);

	function reset() {
		size = 15;
		burst = false;
	}
</script>

<Child
	inflate={(power) => {
		size += power;
		if (size > 75) burst = true;
	}}
	deflate={(power) => {
		if (size > 0) size -= power;
	}}
/>

{#if burst}
	<button onclick={reset}>new balloon</button>
	<span class="boom">💥</span>
{:else}
	<span class="balloon" style="scale: {0.01 * size}">
		🎈
	</span>
{/if}

<style>
	span {
		position: fixed;
		left: 0;
		top: 0;
		width: 100%;
		height: 100%;
		font-size: 100vh;
		text-align: center;
		line-height: 1;
		pointer-events: none;
	}

	.balloon {
		transition: scale 0.2s;
	}

	.boom {
		animation: boom 0.5s forwards;
	}

	@keyframes boom {
		0% {scale: 0.6}
		25% {scale: 0.75}
		100% {scale: 0}
	}
</style>
```

# さいごに
Svelte5で`createEventDispatcher`関数が非推奨になったことにより、`createEventDispatcher`周りのボイラープレートが削減されたり、学習コストが減りました。
propsになったことでどういうイベントを必要としているのかが明確になり、処理が追いやすくなったと思います。