カテゴリー: FrontEnd

vuex-module-decoratorsとTypeScriptでvuexをスマートに書く

はじめに

こちらの記事で紹介したように、Vue CLI 3からVue.jsを手軽にTypeScriptで書くことができるようになりました。しかし、vuexに関してはそのままではTypeScriptで書くのは難しいように思います。

そこで、今回は vuex-module-decorators というサードパーティ製のパッケージを使って、より安全でスマートにvuexを扱う方法を紹介します。

導入

以下のコマンドでパッケージをインストールします。

// 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 での記述を見てみましょう。一般的には以下のような記述になると思います。

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 を使って記述すると以下のようになります。

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 はクラスのプロパティとして定義します。

@Module
class Counter extends VuexModule {
  count: number = 0

mutation

mutation は @Mutation で定義します。 なお、@Mutation を使うためには、事前に Mutation をimportする必要があります。

import { Module, VuexModule, Mutation } from "vuex-module-decorators"

@Module
class Counter extends VuexModule {
  @Mutation
  increment() {
    this.count++
  }
}

action

action は @Action で定義します。 なお、@Action を使うためには、事前に Action をimportする必要があります。

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 はアクセサーとして定義します。

@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する必要があります。

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

動的にモジュールを登録するには以下のようにします。

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

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

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

<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にも様々なサンプルが用意されているので、一度見てみると理解が深まると思います。

おすすめ書籍

     

Hiroki Ono

シェア
執筆者:
Hiroki Ono
タグ: JavaScriptVuejs

最近の投稿

フロントエンドで動画デコレーション&レンダリング

はじめに 今回は、以下のように…

3週間 前

Goのクエリビルダー goqu を使ってみる

はじめに 最近携わっているとあ…

1か月 前

【Xcode15】プライバシーマニフェスト対応に備えて

はじめに こんにちは、suzu…

2か月 前

FSMを使った状態管理をGoで実装する

はじめに 一般的なアプリケーシ…

3か月 前