Vue3 todoアプリ作成 ① ~ compositionAPI 使ってみた ~

# TODOアプリ作成

謎todoアプリ作成 第1弾

[Vue3 todoアプリ作成① ~ compositionAPI ~](https://qiita.com/nakamo-03/items/5f1a8283648f87ab0230)  :point_left:今ここ
[Vue3 todoアプリ作成② ~ Vuex vue-routerを触ってみる ~](https://qiita.com/nakamo-03/items/f5a559d89264a6a2b011) 
[Vue3 todoアプリ作成③ ~ tailwindcss 使ってみた ~ ](https://qiita.com/nakamo-03/items/23320776e7a80b4038e6)

Vue3が３ヶ月前(?)にリリースされましたね:raised_hands:
Vue2とVue3の変更点の記事を眺めているだけでコードを全く書いていなかったので
今回Todoアプリを作成してみました:writing_hand:

作っていくうちに
vue-routerやVuexも試したくなったため　謎todoアプリができあがりました。

正解というものがわからないまま実装していますので、
ここはこうだろ！！など意見ありましたらコメントしていただけますと幸いです。:bow_tone2:

## 完成状態
※この記事のみではこの状態まで説明いたしません。
[完成コード](https://github.com/nakamotoyuto/vite-study)
https://vue3-todoapp.netlify.app/
<a href="https://gyazo.com/0988c4f53127b30817acba8664b60759"><img src="https://i.gyazo.com/0988c4f53127b30817acba8664b60759.gif" alt="Image from Gyazo" width="318"/></a>


## 環境
vite: 1.0.0-rc.1
vue: 3.0.0-rc.2
vue-router: 4
vuex: 4.0.0-rc.2


## Viteでアプリ作成
Viteとはバンドル処理がなく高速に動作するビルドツールでございます。
とにかく早い。。！
以下記事を拝見するとViteについて知ることができますので気になる方は
ご確認よろしくお願いいたします。

[【Vite】 Vue3.0もReactも！ノーバンドルなビルドツール「Vite」を試してみる](https://qiita.com/ryo2132/items/c1530dd590e34e68c494)

[Vite は本当に早いのか ~ Vue CLI と比較 ~](https://qiita.com/jay-es/items/b3bc9c1dc077bc3f7f35)

### プロジェクト作成

```terminal:terminal
//以下コマンド実行　※プロジェクト名をtodo-appとします。
$ npm init vite-app todo-app  
```
作成完了。

### アプリ立ち上げ

```terminal:terminal
//作成したプロジェクトへ移動（todo-app）
$ cd todo-app
//パッケージインストール
$ npm i もしくは yarn
$ npm run dev もしくは yarn dev
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369818/755a7e59-8468-fdb2-d4b6-62c9990e5b46.png)

こんな画面がでます

```ディレクトリ構成:ディレクトリ構成
todo-app
├ node_modules
├ public
│ └ favicon.ico
├ src
│ ├ assets
│ ├ components
│ ├ App.vue
│ ├ index.css
│ └ main.js
├ index.html
├ package-lockjson
└ package.json

```

## コンポーネント作成
componentsディレクトリにて以下ファイル生成


```vuejs:components/TodoList.vue

<template>
</template>

<script lang="ts">
import { defineComponent } from 'vue'

export default defineComponent({
  name: 'TodoList',
});
</script>


```

```vuejs:components/TodoInput.vue

<template>
</template>

<script lang="ts">
import { defineComponent } from 'vue'

export default defineComponent({
  name: 'TodoInput',
});
</script>


```

#### 注意点

-  script lang="ts"とすることで Typescriptで記述することができます。
- コンポーネント作成にてdefineComponentを使用することで型推論することが可能になります。
詳しくは[こちら](https://qiita.com/ryo2132/items/f055679e9974dbc3f977)を確認お願いいたします。


## コンポーネント表示 

仮データを用意し、表示させてみます！

1. App.vueファイルにて TodoListファイルをimport
2. TodoList.vueにて仮データを用意する。
3. TodoInput.vueにてinputとbutton作成。

※TodoInputわざわざ作る必要なくね？となると思われますが、今回emitなど使用してみたかったので作成しました。
お許しを。。

#### reactiveって何ぞや
`data()`の中で`state`を定義していたと思われますが、
`composition api`では `reactive`を使って定義を行います。
と簡単に書いておきます。

以下記事にてわかりやすく説明されています。
[先取りVue 3.x !! Composition API を試してみる](https://qiita.com/ryo2132/items/f055679e9974dbc3f977#%E3%83%AA%E3%82%A2%E3%82%AF%E3%83%86%E3%82%A3%E3%83%96%E3%81%AA%E3%83%97%E3%83%AD%E3%83%91%E3%83%86%E3%82%A3%E3%81%AE%E5%AE%A3%E8%A8%80-ref-reactive)　

```vuejs:App.vue

<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <TodoList />
</template>

<script>
import TodoList from './components/TodoList.vue'

export default {
  name: 'App',
  components: {
    TodoList
  }
}
</script>

```


```vuejs:components/TodoList.vue

<template>
  <div>
    <ul class="todolist">
      <li v-for="todo in state.todoList" :key="todo.todo">{{ todo.todo }}</li>
    </ul>
    <Todo-input />
  </div>
</template>

<script lang="ts">
import { defineComponent, reactive} from 'vue'
import TodoInput from '../components/TodoInput.vue'

export default defineComponent({
  name: 'TodoList',
  components: {
    TodoInput
  },

  setup() {
    // lang="ts"とした場合。 reactiveの中で型定義を行います。
    // 仮データを二つ用意したため、二つtodo定義しています。本来は不必要です。
    const state = reactive<{ todoList: [{todo: String}, {todo: String}];}>({
      todoList: [
          {
            todo: 'todo1',
          },
          {
            todo: 'todo2',
          }

      ]
    });
    return { state };
  }
});

</script>

```

```vuejs:components/TodoInput.vue

<template>
  <input type="text">
  <button >登録</button>
</template>

<script lang="ts">
import { defineComponent } from 'vue'

export default defineComponent({
  name: 'TodoInput',
});

</script>
```

#### 注意点

- templeteの中で`state`などのデータもしくは　`関数`などを記述する際は、`return { state, 関数 }`と記述する必要がある。

#### 結果画面
こんな感じでok

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369818/92fd76d3-b45d-c5d8-91e0-a5650644553c.png)



## 実際にTODO追加
次はtodoを入力し、表示させていきます〜〜

1.カスタムイベント作成
2.emitを使用し、イベント発火させる。

```vuejs:components/TodoList.vue

<template>
  <div>
    <ul class="todolist">
      <li v-for="todo in state.todoList" :key="todo.todo">{{ todo.todo }}</li>
    </ul>
    <Todo-input @add-todo="addTodoAction" />
  </div>
</template>

<script lang="ts">
import { defineComponent, reactive} from 'vue'
import TodoInput from '../components/TodoInput.vue'

export default defineComponent({
  name: 'TodoList',
  components: {
    TodoInput
  },

  setup() {
    const state = reactive<{todoList: Array<{todo: string>;}>({
      todoList: []
    });

    const addTodoAction = (value: string) => {
      state.todoList.push({todo: value})
    };

    return { state, addTodoAction };
  }
});
</script>

```


```vuejs:TodoInput.vue
<template>
  <div>
    <input v-model="todoRef" type="text">
    <button @click="add">登録</button>
  </div>
</template>

<script lang="ts">
import { defineComponent, SetupContext, ref } from 'vue'


export default defineComponent({
  name: 'TodoInput',
  setup(props, context: SetupContext) {
    const todoRef = ref<string>('')

    const add = (e) =>{
      context.emit('add-todo', todoRef.value);
      todoRef.value = ''
    };

    return { add, todoRef};
  }
});
</script>

```
#### 注意点

- `this.$emit`が`context.emit`で使用できる。

> setup(props, props, context: SetupContext)

と記述されているが、setupの関数内の引数は 
第1引数： `props`
第2引数： `context`
と決まっているので

setup(context)と書くことはできない。

#### 結果画面

こちらのコードにしていただきますとこのようになります。
<a href="https://gyazo.com/8a85948199f0db5498e7729b770421e1"><img src="https://i.gyazo.com/8a85948199f0db5498e7729b770421e1.gif" alt="Image from Gyazo" width="318"/></a>

## おわり
ちょっと長くなった感がございますのでここで一旦止めます。
次の記事で完了ボタン、詳細ボタンなどを作成していきたいと思います。

正解というものがわからないまま実装していますので、
ここはこうだろ！！など意見ありましたらコメントしていただけますと幸いです。:bow_tone2:

## 参考記事
[Vue.js ドキュメント](https://v3.ja.vuejs.org/)

[【Vite】 Vue3.0もReactも！ノーバンドルなビルドツール「Vite」を試してみる](https://qiita.com/ryo2132/items/c1530dd590e34e68c494)

[Vite は本当に早いのか ~ Vue CLI と比較 ~](https://qiita.com/jay-es/items/b3bc9c1dc077bc3f7f35)