Nuxt + TypeScript で Vuex を扱うために ~ vuex-module-decorators
はじめに
2019/09/25 執筆
Nuxt TypeScript 公式 も参照して、比較しながら読んで頂けると幸いです。
とりあえず結論(やることまとめ)
vuex-module-decorators
を使います。
yarn add -D vuex-module-decorators
npm install --save-dev vuex-module-decorators
Component 等から import hoge from '~/store'
とインポートできるように、~/store/index.ts
を作成します(当ファイルは基本編集しません)。
import { Store } from 'vuex'
import { initializeStores } from '~/utils/store-accessor'
const initializer = (store: Store<any>) => initializeStores(store)
export const plugins = [initializer]
export * from '~/utils/store-accessor'
自由にストアモジュールを実装してください。下記例は、Nuxt.js + TypeScript + Vuex で簡単な Todo リストを作るチュートリアルで利用している Todo リスト用の Store です。
// 後述の ~/store/todos.ts で使う型定義
export interface Todo {
id: number
text: string
done: boolean
}
import { Module, VuexModule, Mutation } from 'vuex-module-decorators'
import { Todo } from '~/models/Todo'
// stateFactory: true → Vuex をモジュールモードで扱うために指定
@Module({ stateFactory: true, namespaced: true, name: 'todos' })
export default class Todos extends VuexModule {
todos: Todo[] = []
/**
* Todo を追加する
* @param text Todo テキスト
*/
@Mutation
addTodo(text: string) {
const todos: Todo[] = this.todos
// Todo を作成
const todo: Todo = {
// リストがない場合、id = 0
// リストがある場合、id = リストの最終要素の id + 1
id: todos.length === 0 ? 0 : todos[todos.length - 1].id + 1,
text,
done: false
}
// リストに Todo を追加
this.todos.push(todo)
}
/**
* Todo を削除する
* @param todo 削除する Todo インスタンス
*/
@Mutation
remove(todo: Todo) {
this.todos.splice(this.todos.indexOf(todo), 1)
}
/**
* Todo の done(完了状態)を切り替える
* @param todo 完了状態を切り替える対象の Todo インスタンス
*/
@Mutation
toggle(todo: Todo) {
todo.done = !todo.done
}
}
~/utils/store-accessor.ts
にて、自作したストアモジュールを Export します。必要に応じて、ストアの記述を追加してください。
import { Store } from 'vuex'
import { getModule } from 'vuex-module-decorators'
import Todos from '~/store/todos'
// eslint-disable-next-line import/no-mutable-exports ← 必要であれば
let todosStore: Todos
// let someStore: Something
function initializeStores(store: Store<any>): void {
todosStore = getModule(Todos, store)
// someStore = getModule(Something, store)
}
export { initializeStores, todosStore /*, someStore*/ }
最後に、Component からこれらを呼び出します。
※ .vue ファイルの <script lang="ts"></script>
の箇所のみ記載しています。
※ OptionsAPI を使っていますが、ClassAPI、CompositionAPI 自由に変えて OK です。
import Vue from 'vue'
import { todosStore } from '~/store'
export default Vue.extend({
computed: {
todos() {
return todosStore.todos
}
},
methods: {
addTodo(e): void {
todosStore.add(e.target.value)
e.target.value = ''
},
remove(todo: Todo) {
todosStore.remove(todo)
},
toggle(todo: Todo) {
todosStore.toggle(todo)
}
}
})
Nuxt + TypeScript, vuex-module-decorators とかで調べて困ったこと
OptionsAPI, ClassAPI, CompositionAPI って何?
Nuxt + TypeScript で Component 等を記述する時、OptionsAPI, ClassAPI, CompositionAPI の 3 パターンやり方がありますよ、という話。
個人的な見解もまじりますが、これらについての簡単な紹介。
OptionsAPI
Vue 本来の書き方とほとんど変えずに書ける。 逆に言うと、TypeScript っぽさは薄い。
Nuxt, Vue から始めた身としては、最も好み。
ClassAPI
TypeScript っぽく書ける。検索で一番ヒットする。
vue-property-decorator
使うやつ。
かつてはこれが公式推奨だったっぽいが、今は棄却されているらしい。
CompositionAPI
つい最近(2019/09/25 現在)発表されたばかりで、現在 RFC(Request for Comments: とりあえず開発が活発な感じ?)。
今後に備えて CompositionAPI を学ぶのも大いにありだとは思ったが、(日本語の)情報も少なく、初心者には難しかった。
Nuxt + vuex-module-decorators はどうやって使えばいいの?
どうにも、公式ドキュメント に書いてあるのは、Vue.js の情報のよう。
Store の書き方は、公式にあるままで問題ないようだが、果たして Components の方はどう書けばよいのやら。
「Nuxt vuex-module-decorators」と検索すると、Nuxt.js + Typescript + Vuex する現時点のベストと思う方法 にたどり着いた(個人的な見解としては、2019/09/25 現在これが最適解なのかなと)。
上記の記事の内容は、vuex-module-decorators
の 公式 npm パッケージページにも記載されていた。