Svelteのdispatch(ディスパッチ)を図解で理解する。

## SvelteのStoreについて、よく分からなかったので、図を交えて理解してみました。

Svelteのコンポーネントはイベントを発信することもできます。
イベントを発信するにはまず、イベントディスパッチャを作成する必要があります。

```vue
//イベントディスパッチャの作り方

<script>
 import { createEventDispatcher } from 'svelte';
 //svelteからcreateEventDispatcher関数をインポートする。
 const dispatch = createEventDispatcher();
 //createEventDispatcherを実行するとイベントディスパッチャが作成される。
<script>
```
イベントディスパチャーは、第一引数に**イベント名**、第二引数に**プロパティー**を渡します。
第一引数に渡したイベント名でイベントを発信できます。

親コンポーネントでのイベントの受け取り方。
```vue
<子コンポーネント名 on:"受け取るイベント名"={イベントを受け取った時に実行したい関数} >
```

ボタンをクリックすると、"こんにちは"と表示される実装を行います。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547556/ad780204-ae29-ff14-7844-7179e33ba522.png" width="600px">

①子コンポーネントのbutton上でクリックイベントが発火すると、sayHelloメソッドが実行されます。
sayHelloメソッドはdispatchメソッドを実行します。
dispatchメソッドは、第一引数に"message"が渡されているため、messageイベントが発火します。
②親コンポーネントはon:messageで子コンポーネント(Inner)でのmessageイベントを監視しており、messageイベントの発火を検知します。
③messageイベントの発火を検知して、handleMessageメソッドを実行します。
④dispachメソッドの第二引数に渡した値が、eventオブジェクトのdetailキーに格納されて、handleMessageメソッドに渡されます。

## 孫コンポーネントから親コンポーネントにイベントを伝播させる。

もし深くネストされたコンポーネントでイベントをリッスンする場合、中間コンポーネントはイベントを経由して伝播させる必要があります。
下記の様な構造のコンポーネントで、Innnerをクリックした場合に、Appで定義されたメソッドでアラートを出す。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547556/47e3501b-c985-825d-d615-c3cc3bff115a.png" width="500px">

<br>

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547556/a24d7036-ac1f-0c62-4d0e-2307e3c0bd5e.png" width="800px">

①孫コンポーネント(Innner)のbutton上でクリックイベントが発火すると、sayHelloメソッドが実行されます。
sayHelloメソッドはdispatchメソッドを実行します。
dispatchメソッドは、第一引数に"message"が渡されているため、messageイベントが発火します。
②子コンポーネント(Outer)はon:messageで孫コンポーネント(Inner)でのmessageイベントを監視しており、messageイベントの発火を検知します。
③messageイベントの発火を検知して、forwardメソッドを実行します。
④dispachメソッドの第二引数に渡した値が、eventオブジェクトのdetailキーに格納されて、forwardメソッドに渡されます。
⑤さらに子コンポーネントで、massageイベントを発火させます。親コンポーネント（App）でmassageの発火を検知します。
⑥親コンポーネント（App）でmassageイベントの発火を検知したので、handleMessageメソッドが実行されます。
⑦handleMessageメソッドの引数には、fowordの引数のeventからdetailを取り出して(つまり、{text:'こんにちは!'})、渡されます。
(handleMessageメソッドには、またeventとして渡されるので、event.datail.textで取り出すと'こんにちは!'が取り出せます。)

## よりシンプルに実装を修正する。

Svelteでは、イベントを中間で経由する場合に省略して記載することができます。

```vue
//App.svelte

<script>
	import Outer from './Outer.svelte';

	function handleMessage(event) {
		alert(event.detail.text);
	}
</script>

<Outer on:message={handleMessage}/>
```

```vue
//Outer.svelte

<script>
	import Inner from './Inner.svelte';
</script>

<Inner on:message/>

//イベントに値を渡さなかった場合、下位コンポーネントのmessageイベントの発火を監視し、発火を検知した場合に、上位コンポーネントにmessageイベントの発火を知らせます.
//第二引数の値はそのまま、渡されます。
```

```vue
//Innner.svelte

<script>
	import { createEventDispatcher } from 'svelte';

	const dispatch = createEventDispatcher();

	function sayHello() {
		dispatch('message', {
			text: 'こんにちは!'
		});
	}
</script>

<button on:click={sayHello}>
	ボタン
</button>
```
子コンポーネント(Outer)の記述量が少なくなって、すっきりしました。

なお、さらに子供と孫コンポーネントの間に、新たなコンポーネントが入り層が増えたとしても、同様の記述で上位へイベントの発火を伝播させることが可能です。

```vue
//App.svelte

<script>
	import Outer from './Outer.svelte';

	function handleMessage(event) {
		alert(event.detail.text);
	}
</script>

<Outer on:message={handleMessage}/>
```

```vue
//Outer.svelte

<script>
	import Middle from './Middle.svelte';
</script>

<Middle on:message/>
```

```vue
//Middle.svelte

<script>
	import Inner from './Inner.svelte';
</script>

<Inner on:message/>
```

```vue
//Inner.svelte

<script>
	import { createEventDispatcher } from 'svelte';

	const dispatch = createEventDispatcher();

	function sayHello() {
		dispatch('message', {
			text: 'こんにちは!'
		});
	}
</script>

<button on:click={sayHello}>
	ボタン
</button>
```