はじめに
Vuex + Typescriptは相性が悪いと言われており、色々な解決方法が展開されてきました。
そこにNuxt.jsが入ってくると更に混沌としていて、以前公式に書かれていたExampleのコードも(多分放置されて)いつの間にか消えている始末です。
個人的には vuex-module-decorators を使うのが今の時点では楽だし一番良さそうと思いました。
更に先日Nuxt.js + モジュールモードでの実装例が公式にREADMEに追加されていたので、今回はその実装方法を紹介しようと思います。
移り変わりが早い分野なので、近い将来また違うやり方が良い感じになってるかもしれません。未来に読む人は上記のリンク先も参照お願いします。
追記
Nuxt Typescriptの公式に、Storeの実装方法が追記されていました。
ここに記載のvuex-module-decrotaorsを使う方法も記載されていますが、
SSRモードで使用する場合は2019/11月時点で脆弱性があるそうなのでご注意ください!
更に追記
SSRの脆弱性問題について、修正されたようです。
v0.11.0 で治ってるようなので、バージョンに気をつけてご利用ください !!
実装方法
前提
- Nuxt.js + Typescriptの設定ができている
- vuex-module-decorators がinstallされている
Store
まず、store/index.ts
を定義します。これは最初に1回作ったら触りません。
※~/utils/store-accessor
はあとで作成します
import { Store } from 'vuex'
import { initialiseStores } from '~/utils/store-accessor'
const initializer = (store: Store<any>) => initialiseStores(store)
export const plugins = [initializer]
export * from '~/utils/store-accessor'
そして、肝心のMy Storeを作ります。
stateFactory: true
としてexportすることで、NuxtがモジュールモードでStoreを作ってくれます。
import { VuexModule, Module, Mutation, Action } from 'vuex-module-decorators'
import Post from '~/models/Post'
export interface IFeedState {
posts: Post[]
}
@Module({ stateFactory: true, namespaced: true, name: 'feed' })
export default class Feed extends VuexModule implements IFeedState {
posts: Post[] = []
@Mutation
addPost(post: Post) {
this.posts = [...this.posts, post]
}
@Action
async loadPosts() {
const posts = await fetchPosts()
posts.forEach(post => {
this.addPost(post)
})
}
}
store-accessor
作成したstoreをimportするためのユーティリティを実装します。
storeを新しく追加したときはここに追加していきます。
import { Store } from 'vuex'
import { getModule } from 'vuex-module-decorators'
import Feed from '~/store/feed'
let feedStore: Feed
function initialiseStores(store: Store<any>): void {
feedStore = getModule(Feed, store)
}
export { initialiseStores, feedStore }
Component
Component等からstoreにアクセスする時は以下のように書きます。
import { Component, Vue } from 'vue-property-decorator'
import { feedStore } from '~/store'
@Component
export default class FeedPage extends Vue {
get posts() {
return feedStore.posts
}
async created() {
await feedStore.loadPosts()
}
}
これでType SafeにStoreを利用できます。
これだけです!
実装例リポジトリ
最後に上記を実装した完全版のコードを貼っておきます。
https://github.com/suzukenz/nuxt-typescript-demo
以上です!
サードパーティライブラリに依存していたり、accessorのコードがぱっと見気持ち悪かったりが少し気になりますが、Nuxt + Typescript + Vuexの決定版が出てくるまでは自分はこれで突き進んでみようと思います。