1. suzukenz

    Posted

    suzukenz
Changes in title
+Nuxt.js + Typescript + Vuexする現時点のベストと思う方法
Changes in tags
Changes in body
Source | HTML | Preview
@@ -0,0 +1,110 @@
+## はじめに
+
+Vuex + Typescriptは相性が悪いと言われており、色々な解決方法が展開されてきました。
+更にそこにNuxt.jsが入ってくると更に混沌としていて、[以前公式に書かれていたExample](https://nuxtjs.org/examples/typescript-vuex/)もいつの間にか消えている始末です。
+
+個人的には [vuex-module-decorators](https://github.com/championswimmer/vuex-module-decorators) を使うのが今の時点では楽だし一番良さそうと思いました。
+更に先日[Nuxt.js + モジュールモードでの実装例が公式にREADMEに追加されていた](https://github.com/championswimmer/vuex-module-decorators#accessing-modules-with-nuxtjs)のでその紹介です。
+
+**移り変わりが早い分野なので、近い将来また違うやり方が良い感じになってるかもしれません。未来に読む人は上記のリンク先も参照お願いします。**
+
+## 実装方法
+
+### 前提
+- [Nuxt.js + Typescriptの設定ができている](https://ja.nuxtjs.org/guide/typescript/)
+- [vuex-module-decorators](https://github.com/championswimmer/vuex-module-decorators) がinstallされている
+
+### Store
+
+まず、`store/index.ts`を定義します。これは最初に1回作ったら触りません。
+※`~/utils/store-accessor`はあとで作成します
+
+```typescript:~/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を作ってくれます。
+
+```typescript:~/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を新しく追加したときはここに追加していきます。
+
+```typescript:~/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にアクセスする時は以下のように書きます。
+
+```typescript
+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の決定版が出てくるまでは自分はこれで突き進んでみようと思います。