はじめに
こちらの記事で紹介したように、Vue CLI 3からVue.jsを手軽にTypeScriptで書くことができるようになりました。しかし、vuexに関してはそのままではTypeScriptで書くのは難しいように思います。
そこで、今回は vuex-module-decorators というサードパーティ製のパッケージを使って、より安全でスマートにvuexを扱う方法を紹介します。
導入
以下のコマンドでパッケージをインストールします。
1 2 3 4 5 | // for npm npm install-Dvuex-module-decorators // for yarn yarn add-Dvuex-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) constcounter={ state:{count:0}, mutations:{ increment(state){ state.count++ } }, getters:{ twice(state){ returnstate.count*2 } } } conststore=newVuex.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 classCounterextendsVuexModule{ count:number=0 @Mutation increment(){ this.count++ } get twice():number{ returnthis.count*2 } } conststore=newVuex.Store({ state:{}, modules:{ Counter } }) |
vuex 標準の記述と比べて見やすくなったのではないでしょうか。それでは個別に見てみましょう。
state
state はクラスのプロパティとして定義します。
1 2 3 | @Module classCounterextendsVuexModule{ 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 classCounterextendsVuexModule{ @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 classCounterextendsVuexModule{ 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 classCounterextendsVuexModule{ count:number=0 get twice():number{ returnthis.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 classCounterextendsVuexModule{ 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) conststore=newVuex.Store({}) @Module({dynamic:true,store:store,name:"counter"}) classCounterextendsVuexModule{ 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" exportinterfaceICounterState{ count:number } @Module({dynamic:true,store:store,name:"counter",namespace:true}) classCounterextendsVuexModule{ count:number=0 @Mutation increment(){ this.count++ } @Mutation add(val:number){ this.count+=val } @Action({commit:"add"}) add5(){ return5 } get twice():number{ returnthis.count*2 } } export constcounterModule=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) exportinterfaceIRootState{ counter:ICounterState } export defaultnewVuex.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 exportdefaultclassHomeextendsVue{ get count():number{ returncounterModule.count } get twice():number{ returncounterModule.twice } increment(){ counterModule.increment() } addCount(val:number){ counterModule.add(val) } add5(){ counterModule.add5() } } </script> |
さいごに
vuex-module-decorators と TypeScript で vuex をスマートに扱う方法を紹介しました。 vuex-module-decorators のGitHubにも様々なサンプルが用意されているので、一度見てみると理解が深まると思います。