スベルトさん。第1話：Svelteのコンポーネントに属するファンクションを外部からコールする。（読み物 / 連載予定）

# はじめに
:::note alert
これはフィクションです。
:::
:::note info
![read.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24726/20885af3-f2f2-2e72-5dff-b946b527f12c.png)**チームリーダー** 
51くん、Svelte確かやってたよね？！　この会社、他の人はReactかVueしかやってないないからちょっとお願いしたいことが有るんだけれど。
:::
:::note warn
![man.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24726/1ed114ca-97a6-6f66-3805-c0b7f7f12e6f.png)**51** 
まぁ、しょうがないですね。Svelteはマイナーですし、求人は殆どReactかVueですからね。で、お願いは何ですか？
:::
:::note info
![read.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24726/20885af3-f2f2-2e72-5dff-b946b527f12c.png)**チームリーダー** 
ちょっと変わったクライアントさんがいてSvelteで開発をしたいそうなんだよ。それで新人の、まりも君にちょっとSvelteの基礎を教えてくれないかな？　まずは良くあるTo doリストから初めてくれると助かるよ。
:::
:::note warn
![man.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24726/1ed114ca-97a6-6f66-3805-c0b7f7f12e6f.png)**51** 
勿論良いですよ。
:::
:::note info
![read.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24726/20885af3-f2f2-2e72-5dff-b946b527f12c.png)**チームリーダー** 
ひとつ条件が有るんだけれど、To do リストのコンポーネントはロジックと入力のUIを持っていて、登録と削除のUIは外部に出したいんだ、To doコンポーネントには手を入れず、デザイナーが実装時にデザイン自由に変えたいらしいので。
:::
:::note warn
![man.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24726/1ed114ca-97a6-6f66-3805-c0b7f7f12e6f.png)**51** 
わかりました、つまりこうゆうことですね。

**今回作るコンポーネント（To do コンポーネント）：** 
+ To doの保持
+ To doのインプットのUI
+ 登録と削除機能（外部からのコール可）

**外部コンポーネント(サンプル）：** ←デザイナーが触るのはこちらだけにしたい。
+ To doコンポーネント配置
+ 登録、削除のUIとその機能の呼び出し
:::

:::note info
![read.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24726/20885af3-f2f2-2e72-5dff-b946b527f12c.png)**チームリーダー** 
そうそう、多分、そんな感じ。じゃあ、後よろしく～。
:::

# いよいよ実装
:::note info
![asian.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24726/93a66c26-9e48-950c-80b3-9c036d53e776.png)**まりも** 
51さん、よろしくお願いいたします。
:::
:::note warn
![man.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24726/1ed114ca-97a6-6f66-3805-c0b7f7f12e6f.png)**51** 
こちらこそ。ではまずTo doコンポーネントの実装をお願いします。To doはtodoという配列に保持して、登録と削除はそれぞれpushとpopというファンクションに実装してください。
:::
:::note info
![asian.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24726/93a66c26-9e48-950c-80b3-9c036d53e776.png)**まりも** 
できました。
:::
:::note warn
![man.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24726/1ed114ca-97a6-6f66-3805-c0b7f7f12e6f.png)**51**  
おー、早いね。どれどれ。さずが、まりも君！　良い感じに出来てるね。一つだけ。
今回の本題からは外れるけど、この配列を更新するときにpush, popを使うと値が更新されていることにならないのでUIが更新されないんだよ。
:::
```diff_javascript:Todo.svelte
function push() {
+  todo = [value, ...todo];
-  todo.push(value);
}
```
:::note warn
![man.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24726/1ed114ca-97a6-6f66-3805-c0b7f7f12e6f.png)**51**  
こんな風に書き換えると、値が更新されたことになるんだ。
:::

:::note info
![asian.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24726/93a66c26-9e48-950c-80b3-9c036d53e776.png)**まりも** 
なるほどですね。
:::

# さて本題
:::note warn
![man.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24726/1ed114ca-97a6-6f66-3805-c0b7f7f12e6f.png)**51**  
他は良い感じにできているので、本題に移ろう。
先ずはto doコンポーネントのファンクションを外部から参照できるようにしてみよう。
:::

:::note info
![asian.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24726/93a66c26-9e48-950c-80b3-9c036d53e776.png)**まりも** 
いよいよですね。ドキドキします。
:::
:::note warn
![man.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24726/1ed114ca-97a6-6f66-3805-c0b7f7f12e6f.png)**51**  
ドキドキさせて申し訳ないくらい簡単なんだよ。```export```を参照させたいファンクションの前に追加する。それだけ。
:::
```diff_javascript:Todo.svelte
function push() {
	let todo = [];
	let value;
	
+       export function push() {  // exportを追加！
-       function push() {
		if(value && value.trim().length > 0)
			todo = [value, ...todo];
		value = '';
	}
+       export function pop() {  // exportを追加！
-       function pop() {
		todo.pop();
		todo = [...todo];
	}
}
```
:::note info
![asian.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24726/93a66c26-9e48-950c-80b3-9c036d53e776.png)**まりも** 
えっ、それだけですか？！もう~~Rxxt~~とかやってられなくなりますね。
:::
:::note warn
![man.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24726/1ed114ca-97a6-6f66-3805-c0b7f7f12e6f.png)**51**  
では次に、これらファンクションをコールする側を実装してみよう。これも簡単だよ。
先ずは、to doコンポーネントの```this```をバインドして、呼び出し側の変数と紐づける。
:::
```javascript:App.svelte
<script>
  import Todo from './Todo.svelte';
  let todo;
</script>
<Todo bind:this={todo}/>  //thisをバインドして変数todoと紐づけ
```
:::note warn
![man.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24726/1ed114ca-97a6-6f66-3805-c0b7f7f12e6f.png)**51**  
後は、まりも君が想像している通り***this.ファンクション名***という形でファンクションを呼び出すだけだよ。
今回はボタンのクリックで呼び出すように実装してみたよ。
:::

```diff_javascript:App.svelte
<script>
  import Todo from './Todo.svelte';
  let todo;
</script>
<Todo bind:this={todo}/>  //thisをバインドして変数todoと紐づけ
+ <button on:click={todo.push}>Push</button>  //ボタンのクリックイベントでpushファンクションをコール
```

:::note info
![asian.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24726/93a66c26-9e48-950c-80b3-9c036d53e776.png)**まりも** 
簡潔だし、thisをバインドしてそのファンクションを呼び出すっていうのは理にかなっているというか直感的に理解できますね。それに比べると~~Rxxt~~とかは....。
:::

# まとめ
:::note warn
![man.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24726/1ed114ca-97a6-6f66-3805-c0b7f7f12e6f.png)**51**  
じゃあ今回学んだことを整理してみよう。

**ファンクションが呼ばれる側でやること：** 
+ 呼ばれるファンクションに```export```を付加する。

**呼ぶ側でやること：** 
+ 呼びたいコンポーネントの```this```をバインドして、自分の変数と紐づけ。
+ ```this```+ファンクション名でファンクションをコール
:::

:::note info
![asian.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24726/93a66c26-9e48-950c-80b3-9c036d53e776.png)**まりも** 
とても良くわかりました。すっかりSvelteのファンになりそうです。
:::

:::note warn
![man.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24726/1ed114ca-97a6-6f66-3805-c0b7f7f12e6f.png)**51**  
じゃあ、まりも君。最後にコード全体を張っておいてくれるかな？　あとReplのリンクもよろしくね。
:::

:::note info
![asian.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24726/93a66c26-9e48-950c-80b3-9c036d53e776.png)**まりも** 
わかりました！！下に貼っておきます。
見づらいのでスタイルは削除しておきました。Replの方には残っています。
:::

```javascript:ToDo.svelte
<!-- script-->
<script>
	let todo = [];
	let value;
	
	export function push() {
		if(value && value.trim().length > 0)
			todo = [value, ...todo];
		value = '';
	}
	export function pop() {
		todo.pop();
		todo = [...todo];
	}
</script>


<!-- html-->
<input type='text' bind:value={value}>
<ul>
	{#each todo as item}
		<li>{item}</li>
	{/each}
</ul>

```

```javascript:App.svelte
<script>
	import Todo from './Todo.svelte';
	//This gonna be binded to Todo instance
	let todo;

	function onKeyDown(event) {
		// Call Todo instance methods
		event.key === 'Enter' && todo.push();
	}
</script>


<!-- Bind Todo itself and call its' method -->
<div>
	<Todo bind:this={todo}/>
</div>
<!-- buttons calling Todo's method -->
<div>
	<button on:click={todo.push} id='push'>Push</button>	<!-- Call Todo's push method -->
	<button on:click={todo.pop} id='pop'>Pop</button>	<!-- Call Todo's pop method -->
</div>

<svelte:window on:keydown={onKeyDown} />

```

Replのリンクはこちら。[Call function inside of a component from the component](https://svelte.dev/repl/691aadb24f1940b5848efdfa076d0395?version=3.48.0 "Replのリンク")

:::note info
![asian.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24726/93a66c26-9e48-950c-80b3-9c036d53e776.png)**まりも** 
51さん。今回は親が子のファンクションを呼ぶ形でしたが、逆はどうやるんでしょうか？子が親のファンクションを呼びたい時は？
:::

:::note warn
![man.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24726/1ed114ca-97a6-6f66-3805-c0b7f7f12e6f.png)**51**  
流石、まりも君、好奇心旺盛だね。それはまた次の機会まで待っててね。
:::

# 次回予告
:::note info
![112_sazae.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24726/dc910373-d4e8-68e6-349b-0f3923b00fa0.jpeg)
まりもです。先日仮想通貨の下落に伴ってグラボが値下がりしていると聞きました。これを機会に数十枚大人買いしようかと画策している最中です。でも夏は暑そうですね。うちは冷房が無いので冷えピタで毎年しのいでいます。冷えピタはグラボにも有効でしょうか？
さーて次回のスベルトさんは！
 + 子供、親なしじゃ生きられない。親、子なしじゃ生きられない
 + 親は子供を選べるが、子供は親を選べない
 + 子供、孫、ひ孫までじいちゃんを呼び出す
 
 の三本です！
:::

:::note alert
これはフィクションです。
:::
:::note alert
Markdownの使い方が本来意図された使い方と異なるなどの批判は受け付けません。
:::