nuxt-ts day3:型安全なVuexでtodoリストを作る
3日目。
https://nuxt-ts-sample.netlify.app/todolist
作った。
compotisionAPI で todoリストを作る
todolist.vue
import { reactive } from "@vue/composition-api";
interface Todo {
todo: string,
todos: string[]
}
export default {
setup() {
const state = reactive<Todo>({
todo: '',
todos: []
})
const addTodo = () => {
state.todos.push(state.todo)
state.todo = ''
}
const removeTodo = (index: number) => state.todos.splice(index,1)
return {
state,
addTodo,
removeTodo
}
}
}
シンプルな形です。
Vuex を導入する
公式のドキュメントに従って進めていきます。そもそもvuexが型推論と相性が悪いようなので、色々と過程を踏む必要があるらしい。
モジュールとして、store の内容を記述します。
store\todo.ts
import { Module, VuexModule, Mutation } from 'vuex-module-decorators'
@Module({
name: 'todo',
stateFactory: true,
namespaced: true
})
export default class Todos extends VuexModule {
private todos: string[] = ['task1']
public get getTodos () {
return this.todos
}
@Mutation
public add (todo: string) {
this.todos.push(todo)
}
@Mutation
public remove (id: number) {
this.todos.splice(id, 1)
}
}
ここでモジュールを store として読み込みます。
store\index.ts
import { Store } from 'vuex'
import { initialiseStores } from '~/utils/store-accessor'
const initializer = (store: Store<any>) => initialiseStores(store)
export const plugins = [initializer]
export * from '~/utils/store-accessor'
アクセサーを作ります。これでcomponentから TodoStore が参照できるようになりました。
新たに store を作りたいときはここに追記していく必要があります。
utils\store-accessor.ts
/* eslint-disable import/no-mutable-exports */
import { Store } from 'vuex'
import { getModule } from 'vuex-module-decorators'
import Todo from '~/store/todo'
let TodoStore: Todo
function initialiseStores (store: Store<any>): void {
TodoStore = getModule(Todo, store)
}
export { initialiseStores, TodoStore }
todolistコンポーネントを store 仕様に書き換えます。
todolist.vue
import { defineComponent, reactive, computed } from '@vue/composition-api'
import { TodoStore } from '~/store'
interface Todo {
todo: string
}
export default defineComponent({
setup () {
const state = reactive<Todo>({
todo: ''
})
const todos = TodoStore
const todolist = computed(() => todos.getTodos)
const addTodo = () => {
todos.add(state.todo)
state.todo = ''
}
const removeTodo = (index: number) => {
todos.remove(index)
}
return {
state,
todolist,
addTodo,
removeTodo
}
}
})
tailwindcss の使用感
template部はこんな感じに。tailwindcssをやっている。
todolist.vue
<template>
<div class="justify-center items-center text-center max-w-md mx-auto">
<h1>Todoリスト</h1>
<div class="flex">
<input v-model="state.todo" class="bg-white focus:outline-none focus:shadow-outline border border-gray-300 rounded-lg py-2 px-4 block w-full leading-normal" placeholder="taskを入力してください">
<button class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded w-20 ml-3" @click="addTodo">
追加
</button>
</div>
<br>
<li v-for="(todo, index) in todolist" :key="index" class="py-1 text-left">
{{ todo }}
<button class="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 ml-3 rounded-full" @click="removeTodo(index)">
delete
</button>
</li>
</template>
現段階ではいまいち便利さを図り損ねている。微調整がかんたんなのは嬉しいけど、新たなコンポーネントを作るたびに設定しなきゃなのが面倒ですね。CSSの勉強にはなりそうだ。