2019年6月4日火曜日

NuxtでTypeScriptを使うときのVeux.storeの設定方法

NuxtTypeScript で構築した時に 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.jsv3.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 のオプションに namespacedPathtarget:'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 件のコメント:

コメントを投稿