Help us understand the problem. What is going on with this article?

Nuxt.js + Typescript + Vuexする現時点のベストと思う方法

はじめに

Vuex + Typescriptは相性が悪いと言われており、色々な解決方法が展開されてきました。
そこにNuxt.jsが入ってくると更に混沌としていて、以前公式に書かれていたExampleのコードも(多分放置されて)いつの間にか消えている始末です。

個人的には vuex-module-decorators を使うのが今の時点では楽だし一番良さそうと思いました。
更に先日Nuxt.js + モジュールモードでの実装例が公式にREADMEに追加されていたので、今回はその実装方法を紹介しようと思います。

移り変わりが早い分野なので、近い将来また違うやり方が良い感じになってるかもしれません。未来に読む人は上記のリンク先も参照お願いします。

追記

Nuxt Typescriptの公式に、Storeの実装方法が追記されていました。
ここに記載のvuex-module-decrotaorsを使う方法も記載されていますが、
SSRモードで使用する場合は2019/11月時点で脆弱性があるそうなのでご注意ください!

https://typescript.nuxtjs.org/ja/cookbook/store.html

更に追記

SSRの脆弱性問題について、修正されたようです。
v0.11.0 で治ってるようなので、バージョンに気をつけてご利用ください !!

実装方法

前提

Store

まず、store/index.tsを定義します。これは最初に1回作ったら触りません。
~/utils/store-accessorはあとで作成します

~/store/index.ts
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を作ってくれます。

~/store/feed.ts
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を新しく追加したときはここに追加していきます。

~/utils/store-accessor.ts
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の決定版が出てくるまでは自分はこれで突き進んでみようと思います。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした