はじめに
こちらの記事で紹介したように、Vue CLI 3からVue.jsを手軽にTypeScriptで書くことができるようになりました。しかし、vuexに関してはそのままではTypeScriptで書くのは難しいように思います。
そこで、今回は vuex-module-decorators というサードパーティ製のパッケージを使って、より安全でスマートにvuexを扱う方法を紹介します。
導入
以下のコマンドでパッケージをインストールします。
1 2 3 4 5 | // for npm npm install -D vuex-module-decorators // for yarn yarn add -D vuex-module-decorators |
TypeScriptを使用する場合は tsconfig.json に以下の設定をします。
- “experimentalDecorators”: true,
- “importHelpers”: true,
どのように記述するか
初めに
vuex-module-decorators での記述を見る前に、通常の vuex での記述を見てみましょう。一般的には以下のような記述になると思います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | import Vue from "vue" import Vuex from "vuex" Vue.use(Vuex) const counter = { state: { count: 0 }, mutations: { increment (state) { state.count++ } }, getters: { twice (state) { return state.count * 2 } } } const store = new Vuex.Store({ state: {}, modules: { counter } }) |
これを TypeScript と vuex-module-decorators を使って記述すると以下のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | import Vue from "vue" import Vuex from "vuex" import { Module, VuexModule, Mutation } from "vuex-module-decorators" Vue.use(Vuex) @Module class Counter extends VuexModule { count: number = 0 @Mutation increment() { this.count++ } get twice():number { return this.count * 2 } } const store = new Vuex.Store({ state: {}, modules: { Counter } }) |
vuex 標準の記述と比べて見やすくなったのではないでしょうか。それでは個別に見てみましょう。
state
state はクラスのプロパティとして定義します。
1 2 3 | @Module class Counter extends VuexModule { count: number = 0 |
mutation
mutation は @Mutation で定義します。 なお、@Mutation を使うためには、事前に Mutation をimportする必要があります。
1 2 3 4 5 6 7 8 9 | import { Module, VuexModule, Mutation } from "vuex-module-decorators" @Module class Counter extends VuexModule { @Mutation increment() { this.count++ } } |
action
action は @Action で定義します。 なお、@Action を使うためには、事前に Action をimportする必要があります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | import { Module, VuexModule, Mutation, Action } from "vuex-module-decorators" @Module class Counter extends VuexModule { count: number = 0 @Mutation add(val: number) { this.count += val } @Action({ commit: "add" }) add5() { return } } |
getter
getter はアクセサーとして定義します。
1 2 3 4 5 6 7 8 | @Module class Counter extends VuexModule { count: number = 0 get twice():number { return this.count * 2 } } |
async MutationAction
@MutationAction を使うと複数の state を一度に commit することができます。return はJSON形式で指定します。なお、@MutationAction を使うためには、事前に MutationAction をimportする必要があります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | import { Module, VuexModule, MutationAction } from "vuex-module-decorators" @Module class Counter extends VuexModule { count1: number = 0 count2: number = 0 @MutationAction({ mutate: ["count1", "count2"] }) async setAll() { return { count1: 10, count2: 20 } } } |
Dynamic Module
動的にモジュールを登録するには以下のようにします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | import Vue from "vue" import Vuex from "vuex" import { Module, VuexModule, Mutation } from "vuex-module-decorators" Vue.use(Vuex) const store = new Vuex.Store({}) @Module({ dynamic: true, store: store, name: "counter" }) class Counter extends VuexModule { count: number = 0 @Mutation increment() { this.count++ } } |
サンプルコード
最後に、 vuex-module-decorators を使ったサンプルコードを紹介します。
vuex
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | import { Module, VuexModule, Mutation, Action, getModule } from "vuex-module-decorators" import store from "@/store/store" export interface ICounterState { count: number } @Module({ dynamic: true, store: store, name: "counter", namespace: true }) class Counter extends VuexModule { count: number = 0 @Mutation increment() { this.count++ } @Mutation add(val: number) { this.count += val } @Action({ commit: "add" }) add5() { return 5 } get twice():number { return this.count * 2 } } export const counterModule = getModule(Counter) |
store
1 2 3 4 5 6 7 8 9 10 11 | import Vue from "vue" import Vuex from "vuex" import { ICounterState } from "./modules/counter" Vue.use(Vuex) export interface IRootState { counter: ICounterState } export default new Vuex.Store<IRootState>({}) |
component
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | <template></template> <script lang="ts"> import { Component, Vue } from "vue-property-decorator" import { counterModule } from "@/store/modules/counter" @Component export default class Home extends Vue { get count(): number { return counterModule.count } get twice(): number { return counterModule.twice } increment() { counterModule.increment() } addCount(val: number) { counterModule.add(val) } add5() { counterModule.add5() } } </script> |
さいごに
vuex-module-decorators と TypeScript で vuex をスマートに扱う方法を紹介しました。 vuex-module-decorators のGitHubにも様々なサンプルが用意されているので、一度見てみると理解が深まると思います。