Nuxt
を TypeScript
で構築した時に Vuex.store
の構成をどうしたらいいかを考えてみました。
結論としては vuex-class-component
を使用してモジュールモードで構成する、という感じになりました。
完成したプロジェクトは以下のリポジトリになります。
https://github.com/TAC/nuxt-vuex-typescript-example
簡単なカウンターを作成しました。
環境
- | version |
---|---|
OS | Windows10 |
Node.js | v8.15.0 |
Nuxt.js | v2.7.1 |
どのモジュールがいいのか?
Vuex.store
を簡潔にかけるようにするモジュールはいくつかあって、以下の2つが主に使われてるようでした。
vuex-class-component
https://github.com/michaelolof/vuex-class-component
vuex-module-decorators
https://github.com/championswimmer/vuex-module-decorators
Nuxt
では store
ディレクトリ以下にファイルを配置すれば自動で Vuex
のモジュールモードで構築してくれます。
ただし、 store/index.ts
が関数を返すとクラシックモードになり、その恩恵を受けることができません。
また、各モジュールのファイルも関数ではなくオブジェクトを返す必要があり、それができるのが vuex-class-component
でした。
また、Nuxt.js
は v3.0.0
ではクラシックモードが非対応になるようなので、それを考慮に入れての選択になります。
ディレクトリ構成
以下のような構成を考えてみました。
src/store/index.ts
+- modules/
+- counter.ts
modules
に機能毎に分けたモジュールを作成していく感じです。
models
とか作ってDBのテーブル毎などに分けたモジュールを作成してもいいかもしれない。
counter.ts
デコレータを使って以下のように記述します。
import {
VuexModule,
Module,
action,
getter,
mutation
} from 'vuex-class-component'
interface Counter {
value: number
}
@Module({ namespacedPath: 'modules/counter/', target: 'nuxt' })
export class CounterStore extends VuexModule implements Counter {
@getter value = 0
@mutation
public SET_VALUE(value: number) {
this.value = value
}
@action()
public increment(value: number) {
this.SET_VALUE(this.value + value)
}
@action()
public decrement(value: number) {
this.SET_VALUE(this.value - value)
}
}
export default CounterStore.ExtractVuexModule(CounterStore)
ポイントは2つあって、1つは @Module
のオプションに namespacedPath
と target:'nuxt'
を指定するところです。
もう1つは、最後の行で ExtractVuexModule
を使ってオブジェクト形式で export してあげるところです。
これで Vuex.store
のモジュールモードに対応できました。
index.ts
index.ts
もデコレータを使って記述しようとしたのですが、 nuxtServerInit
の定義がどうしてもできなかったので、デコレータを使わずに記述します。
export const actions = {
nuxtServerInit: ({ commit }) => {
commit('modules/counter/SET_VALUE', 20)
}
}
ここでは modules/counter
の初期化を行ってみました。
呼び出すComponent
components/Counter.vue
を作成します。
<template lang="pug">
div [counter]
div {{ counter }}
div
button(@click="increment") +
button(@click="decrement") -
</template>
<script lang="ts">
import { Component, Vue } from 'nuxt-property-decorator'
@Component
export default class Counter extends Vue {
get counter() {
return this.$store.getters['modules/counter/value']
}
public increment() {
this.$store.dispatch('modules/counter/increment', 1)
}
public decrement() {
this.$store.dispatch('modules/counter/decrement', 1)
}
}
</script>
呼び出す箇所は通常の使い方と同じです。
これでごちゃごちゃしがちな store
周りをスッキリとかけるようになったかと思います。
Written with StackEdit.
0 件のコメント:
コメントを投稿