Svelte3 親子コンポーネント間でデータを受け渡す


# 親 → 子に値を渡す
https://svelte.dev/tutorial/declaring-props
チュートリアルを参考にして書いてみる。

- 親コンポーネント： 子コンポーネントのプロパティに設定するだけ
- 子コンポーネント： `export`を付けて変数宣言しとくだけ

親の値が変更された場合、子の値も自動で変わる。

__親コンポーネント__

```html
<script>
	import Child from './Child.svelte';
	let parentCnt = 0
	let childCnt = 0
	function add() {
		parentCnt++;
	}
</script>

<div>親: {parentCnt}</div>
<div>子: {childCnt}</div>
<button on:click="{add}">Parent Button</button>

<Child parentCnt={parentCnt} childCnt={childCnt}/>
```

__子コンポーネント__

```html
<script>
	export let parentCnt;
	export let childCnt;
	function add() {
		childCnt++;
	}
</script>

<div>親: {parentCnt}</div>
<div>子: {childCnt}</div>
<button on:click="{add}">Child Button</button>
```

上のコードを実行したときの動きは以下のようになる。

- `Parent Button`を押す
    - 親の`parentCnt`がカウントアップされる
    - 子の`parentCnt`が親と同じ値に書き換わる
- `Child Button`を押す
    - 子の`childCnt`がカウントアップされる
    - 親の`childCnt`は変化しない

# 子 → 親に値を渡す
https://svelte.dev/tutorial/component-events
`dispatcher`を使って親コンポーネントイベントを呼んで渡せばよいみたい。

最初に使ったコードを使って、`Child Button`が押されたら
親の`childCnt`にも子コンポーネントでボタンをした数を渡すようにしてみる。

- 親コンポーネントの変更点
	- 子コンポーネントに`on:updateChild`イベントを追加
- 子コンポーネントの変更点
	- `createEventDispatcher`をインポート
	- `dispatch`を実行して`updateChild`イベントを発火する

__親コンポーネント__

```html
<script>
	import Child from './Child.svelte';
	let parentCnt = 0
	let childCnt = 0
	function add() {
		parentCnt++;
	}
	function updateChild(event) {
		childCnt = event.detail.cnt
	}
</script>

<div>親: {parentCnt}</div>
<div>子: {childCnt}</div>
<button on:click="{add}">Parent Button</button>

<Child parentCnt={parentCnt} childCnt={childCnt} on:updateChild={updateChild}/>
```

__子コンポーネント__

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

	const dispatch = createEventDispatcher();

	export let parentCnt;
	export let childCnt;
	function add() {
		childCnt++;
		dispatch('updateChild', { cnt: childCnt });
	}
</script>

<div>親: {parentCnt}</div>
<div>子: {childCnt}</div>
<button on:click="{add}">Child Button</button>
```

# 孫 → 親に値を渡す
https://svelte.dev/tutorial/event-forwarding
親 → 子 → 孫みたいに何個かコンポーネントがネストされている場合に
孫から親までデータ渡したいときの書き方。

__親コンポーネント（変更無し）__

```html
<script>
	import Child from './Child.svelte';
	let parentCnt = 0
	let childCnt = 0
	function add() {
		parentCnt++;
	}
	function updateChild(event) {
		childCnt = event.detail.cnt
	}
</script>

<div>親: {parentCnt}</div>
<div>子: {childCnt}</div>
<button on:click="{add}">Parent Button</button>

<Child {parentCnt} {childCnt} on:updateChild={updateChild}/>
```

__子コンポーネント__

```html
<script>
	import Child2 from './Child2.svelte';
	import { createEventDispatcher } from 'svelte';

	const dispatch = createEventDispatcher();

	export let parentCnt;
	export let childCnt;

	function updateChild(event) {
		dispatch('updateChild', event.detail);
	}
</script>

<Child2 {parentCnt} {childCnt} on:updateChild={updateChild}/>
```

__孫コンポーネント__

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

	const dispatch = createEventDispatcher();

	export let parentCnt;
	export let childCnt;
	function add() {
		childCnt++;
		dispatch('updateChild', { cnt: childCnt });
	}
</script>

<div>親: {parentCnt}</div>
<div>子: {childCnt}</div>
<button on:click="{add}">Child Button</button>
```

孫から子の`updateChild` → 子から親の`updateChild`にイベントを伝達していく感じ。

中間コンポーネントになる子コンポーネントに関しては
特にやること無ければ以下のように`dispatch`を省略して書くことが可能。

コンポーネントイベントに何もイベント設定しなければイベントが転送される仕組みになっている。

```html
<script>
	import Child2 from './Child2.svelte';

	export let parentCnt;
	export let childCnt;
</script>

<Child2 {parentCnt} {childCnt} on:updateChild/>
```

# メモ
## 省略系
親コンポーネントの変数名が、子コンポーネントのプロパティと同じ名前なら以下のようにキーを省略することも可能

```html
<Child childCnt={childCnt}/>
↓
<Child {childCnt}/>
```

## キャメルケース・スネークケースのプロパティ
子コンポーネントに定義されているプロパティ名がキャメルケース・スネークケースの時は
子に定義されているプロパティ名をそのままの使う。

※Vuejsみたいにケバブケースにする必要はない

```html
<Child hoge={1} hogeHoge={2} hoge_hoge={3}/>
```

```html
<script>
	export let hoge;
	export let hogeHoge;
	export let hoge_hoge;
</script>
```

## オブジェクトが持つプロパティを一気に子に渡す
オブジェクトのキーを全部、子コンポーネントに渡したい場合。

__親コンポーネント__

```html
<script>
	import Child from './Child.svelte';
	let obj = { hoge: 1, fuga: 'fuga' }
</script>

<Child hoge={obj.hoge} fuga={obj.fuga}/>
```

__子コンポーネント__

```html
<script>
	export let hoge;
	export let fuga;
</script>
```

上のようにバラバラで渡してもいいけど以下のようにスプレッド構文使ったほうが楽。

```html
<Child {...obj}/>
```

以下のようにオブジェクトを子に渡す事もできる。
型定義とかしてる訳じゃないので何入ってるか分からないのであまり良いとは思えないけど。

```html
<Child hoge={obj}/>
```


## DOMイベントを親に転送する
`dispatch`を使って親のDOMイベントを発火させる事もできるが
イベント転送することでより簡単に書くことができる。

__親コンポーネント__

```html
<script>
	import Child from './Child.svelte';
	let cnt = 0
	function add() {
		cnt++;
	}
</script>

<div>cnt: {cnt}</div>
<Child {cnt} on:click={add}/>
```

__子コンポーネント__

```html
<script>
	export let cnt;
</script>

<button on:click>Add</button>
```

上の記述と、下の`dispatch`を使った記述は同等。


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

	const dispatch = createEventDispatcher();

	export let cnt;
	function click() {
		dispatch('click');
	}
</script>

<button on:click="{click}">Add</button>
```

### ちょい注意
ボタンクリック時とかのイベント転送については
`on:click`とか`on:change`とかのDOMイベントの話で
オリジナルのコンポーネントイベントについてはダメっぽい。

なので以下のコードはイベントが発火されず何もおこならない。

__親コンポーネント__

```html
<script>
	import Child from './Child.svelte';
	let cnt = 0
	function add() {
		cnt++;
	}
</script>

<div>cnt: {cnt}</div>
<Child {cnt} on:hoge={add}/>
```

__子コンポーネント__

```html
<script>
	export let cnt;
</script>

<button on:hoge>Add</button>
```