103
73

More than 3 years have passed since last update.

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

Last updated at Posted at 2019-08-15

はじめに

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

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

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

追記

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

更に追記

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

103
73
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
103
73