React で書いたコードを Svelte に書き換えて記述量の少なさを実感

# ユーザーリストアプリを作成する

以前 React を用いて作成した[ユーザーリストを表示するアプリ](https://qiita.com/itizawa/items/075d06fc17f9c5ca5ff7)を Svelte でも作成してみます。  

## まずは input form を作成する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394488/95d3dd2e-f189-662d-d57d-a15cff030c08.png)


```html:InputForm.svelte
<script>
  let firstName = ''
  let lastName = ''

  function addUser() {
    console.log(`${firstName} ${lastName} を追加します`)
  }
</script>

<div className="input-field">
  <label htmlFor="first_name">First Name</label>
  <input id="first_name" type="text" bind:value={firstName} />
</div>
<div className="input-field">
  <label htmlFor="last_name">Last Name</label>
  <input id="last_name" type="text" bind:value={lastName} />
</div>
<button class="btn waves-effect waves-light" on:click={addUser}>Add</button>
```
 
React と比べてかなりシンプルに書けているようです。
script タグ内で変数を宣言し、使いたい場所に変数を設置します。
React のように値を setState するための関数は必要ありません。代わりに必要なのは value に bind: をつけるだけです。

- 参考
    - https://svelte.dev/tutorial/text-inputs

## 関数を子コンポーネントに渡す

追加するユーザーリストは親コンポーネントで値を保存しておきたいので、ユーザーを追加する処理は親コンポーネントで実装します。
Svelte も function を子コンポーネントに渡すことが可能です。

```html:App.svelte
<script>
  import InputForm from './InputForm.svelte'

  let users = []

  function addUser(form) {
    users = [
      ...users,
      {
        firstName: form.firstName,
        lastName: form.lastName,
      },
    ]
  }
</script>
```
親コンポーネントの script 内で addUser を定義して `<InputForm {addUser} />` で子コンポーネントに渡します。
ショートハンドを用い短いコードで実現できます。

```html:InputForm.svelte
<script>
  export let addUser

  let form = {
    firstName: '',
    lastName: '',
  }

  function onClickAddButton() {
    addUser(form)
    form.firstName = ''
    form.lastName = ''
  }
</script>

<div className="input-field">
  <label htmlFor="first_name">First Name</label>
  <input id="first_name" type="text" bind:value={form.firstName} />
</div>
<div className="input-field">
  <label htmlFor="last_name">Last Name</label>
  <input id="last_name" type="text" bind:value={form.lastName} />
</div>
<button class="btn waves-effect waves-light" on:click={onClickAddButton}>
  Add
</button>
```
InputForm.svelt を改修しました。
親コンポーネントから渡ってきた関数は、 `export let addUser` で使用できるようになります。  
Object の値の更新を React で使用するときは Object 丸ごと更新されてしまうためスプレット構文を使用するなどして工夫する必要がありました。
しかし、 Svelte では直接入れ子になった値を更新するので記述を減らせます。

## ユーザーを表示するテーブルを実装する

```html:UserList.svelte
<script>
  export let users
</script>

<table>
  <thead>
    <tr>
      <th>First Name</th>
      <th>Last Name</th>
    </tr>
  </thead>
  <tbody>
    {#each users as user}
      <tr>
        <td>{user.firstName}</td>
        <td>{user.lastName}</td>
      </tr>
    {/each}
  </tbody>
</table>
```
Reactにおいて map で実現していたことを each を使用して実現しています。
テンプレートエンジンらしい書き方なのかなぁと思います。
key を設定する必要のないところも違いですね。

- 参考
    - https://svelte.dev/tutorial/each-blocks

## 完成

![名称未設定.mov.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394488/9ea4094c-5c03-ee0c-47fc-680ff30dc025.gif)


[完成版のコードはこちら GitHub に飛びます](https://github.com/itizawa/Svelte-library/tree/feat/create-user-list-app/svelte-app)

### 所感
React : 約 130 行 ⇨ Svelte : 約 80 行 :tada: 
個人的には `this.state.hoge` など、 React の書き方に慣れていて少ないコードに少し不安感を覚えましたが、慣れれば快適に書けそうです。
フレームワークを触ったことない方や Vue 使いには取っつき易く良い開発体験を感じられると思うのでぜひ試してみてください。