はじめに

Vuex で dispatch するとき、action 名とかどうやって取ってくるのがベストなのかなと

補完を効かせてタイポ無くメソッド呼びたい!

ということで最近は Vuex 使うときはもっぱら vuex-module-decorators ばかり使っています。

導入

↓ 通りに ~/store/index.ts を作成して ~/utils/store-accessor.ts に書いてある store モジュールを展開する感じ

https://github.com/championswimmer/vuex-module-decorators#accessing-modules-with-nuxtjs

~/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';

~/utils/store-accessor.ts:

/* eslint-disable import/no-mutable-exports */
import { Store } from 'vuex';
import { getModule } from 'vuex-module-decorators';

import News from '@/store/news';

let newsStore: News;

function initialiseStores(store: Store<any>): void {
  newsStore = getModule(News, store);
}

export { initialiseStores, newsStore };

サンプルで NEWS を取得する Store を書いていきます

~/store/news.ts

import { Module, VuexModule, Mutation, Action } from 'vuex-module-decorators';

// 何かしらのapiメソッド
import api from '@/api';

interface News {
  id: string;
  title: string;
  body: string;
}

@Module({ name: 'news', namespaced: true, stateFactory: true })
export default class News extends VuexModule {
  public list: News[] = [];

  public one: News | null = null;

  @Mutation
  public setList(list: News[]) {
    this.list = list;
  }

  @Mutation
  public setOne(value: News) {
    this.one = value;
  }

  @Action({ rawError: true })
  public async fetchList() {
    // News取得のAPI
    await api
      .newsList()
      .then((res) => {
        this.setList(res.data);
      })
      .catch((err) => {
        throw Error(err);
      });
  }

  @Action({ rawError: true })
  public async fetchOne(id: string) {
    // News取得のAPI
    await api
      .newsGet(id)
      .then((res) => {
        this.setOne(res.data);
      })
      .catch((err) => {
        throw Error(err);
      });
  }
}

呼び出し側は ↓ のように書きます

~/pages/index.vue

<template>
	<div>
		<ul>
			<li v-for="item in list" :key="item.id">
				<nuxt-link :to="`/news/${item.id}`">
					{{ item.title }}
				</nuxt-link>
			</li>
		</ul>
	</div>
</template>

<script>
import Vue from 'vue;
import { newsStore } from '@/store';

export default Vue.extend({
	// middleware か asyncDataで取得
	async middleware({ error }) {
		await newsStore.fetchList()
			.catch(err => error(err));
	},
	computed: {
		list() {
			return newsStore.list;
		}
	}
});
</script>

おわり

1 つ、2 つの Store だと恩恵があまり感じられませんが、

数が増えてくるといちいちメソッド名、state 名は覚えてられないです。

なので補完でタイポ無し、それっぽそうな名前が選べるのでめちゃ便利です