LoginSignup
10
8

More than 1 year has passed since last update.

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

Last updated at Posted at 2020-12-28

TODOアプリ作成

謎todoアプリ作成 第1弾

Vue3 todoアプリ作成① ~ compositionAPI ~ :point_left:今ここ
Vue3 todoアプリ作成② ~ Vuex vue-routerを触ってみる ~
Vue3 todoアプリ作成③ ~ tailwindcss 使ってみた ~

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

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

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

完成状態

※この記事のみではこの状態まで説明いたしません。
完成コード
https://vue3-todoapp.netlify.app/
Image from Gyazo

環境

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」を試してみる

Vite は本当に早いのか ~ Vue CLI と比較 ~

プロジェクト作成

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

作成完了。

アプリ立ち上げ

terminal
//作成したプロジェクトへ移動(todo-app)
$ cd todo-app
//パッケージインストール
$ npm i もしくは yarn
$ npm run dev もしくは yarn dev

image.png

こんな画面がでます

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

コンポーネント作成

componentsディレクトリにて以下ファイル生成

components/TodoList.vue

<template>
</template>

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

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


components/TodoInput.vue

<template>
</template>

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

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


注意点

  • script lang="ts"とすることで Typescriptで記述することができます。
  • コンポーネント作成にてdefineComponentを使用することで型推論することが可能になります。
    詳しくはこちらを確認お願いいたします。

コンポーネント表示

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

  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 を試してみる 

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>

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>

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

実際にTODO追加

次はtodoを入力し、表示させていきます〜〜

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

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>

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.$emitcontext.emitで使用できる。

setup(props, props, context: SetupContext)

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

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

結果画面

こちらのコードにしていただきますとこのようになります。
Image from Gyazo

おわり

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

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

参考記事

Vue.js ドキュメント

【Vite】 Vue3.0もReactも!ノーバンドルなビルドツール「Vite」を試してみる

Vite は本当に早いのか ~ Vue CLI と比較 ~

10
8
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
8