Coding 2019.12.02

Nuxt.jsで理解するVuexのあんなことやこんなこと

記事のアイキャッチ画像

Vuexを使うと様々な局面でアプリケーション開発の助けになります。複雑な状態管理を自作で実装する前にVuexの使い所と使い方を見ていきませんか?

はじめに

みなさんVuexをご存知ですか?
よほど簡易なアプリケーション開発でなければ必須級の機能になるVuex。
でも、Vuexってなんだか難しそうで尻込みしている人もまだまだたくさんいると思います。
今回はそんなVuexをNuxt.jsを使って理解していこうと思います。

まだNuxt.jsを使ったことがない人はこれを機にぜひNuxtデビューをしてみてください。きっと大好きになれる最高のフレームワークです。

Nuxtの始め方はこちら

Vuexとは

まずはVuexについて。
VuexとはVueが用意してくれている状態管理ライブラリです。
20191202 01
上の図のように、Action、Mutationを使ってState(状態)を管理していきます。

Action、Mutation、Stateはどのコンポーネントからでもアクセス可能で、かつ状態の一元管理が可能なこともあり、便利に使えるデータストレージのような存在です。

Actionを実行することをdispatch(ディスパッチ)、Mutationを実行することをcommit(コミット) と呼ぶので覚えておいてください。

Vuexの使い所

上述したようにVuexは、

  • どのコンポーネントからでもアクセス可能
  • 状態の一元管理が可能

という特徴を持っています。
20191202 02
これらの特徴がどういった悩みや問題を解決してくれるか見ていきましょう。
ここではモーダルの表示制御を行うdispModalFlgを例に考えていきたいと思います。

異なるコンポーネント間で管理する場合

異なるコンポーネント間で、dispModalFlgを管理しようとするケースです。

dispModalFlgをどのコンポーネントに持つか悩んだり、dispModalFlgを持ったコンポーネントにそれぞれのコンポーネントからアクセスするのが面倒くさくなりそうです。

こんな場合にVuexを使えば、それぞれのコンポーネントからVuexにアクセスしてdispModalFlgを更新するだけで、すっきりと簡単に実装することが出来ます。

深いネスト関係にあるコンポーネント間で管理する場合

親コンポーネントからはるか深くにある孫コンポーネントでdispModalFlgを管理しようとするケースです。

ネストしているすべてのコンポーネントでdispModalFlgをpropsとして渡すいわゆる"propsリレー"状態になったり、dispModalFlgを更新するために親コンポーネントまで再び遡らないといけなかったりと、このケースも少々面倒になりそうです。

が、この場合もVuexを使えば、どれだけネストが深かろうとそれぞれのコンポーネントからVuexにアクセスしてdispModalFlgを管理すれば良くなるので、実装はとても楽になります。

Vuexの使い方

ここからは、Nuxtを使って実際にVuexの使い方を見ていきましょう。
Nuxtにはクラシックモードとモジュールモードという2つのストアの利用の仕方があるのですが、前者のクラシックモードに関しては廃止予定になっているので、ここではモジュールモードを前提に話を進めていきます。
2つのモードの違いが気になる方は、Nuxtの公式ページをご覧ください。

では、実際に使っていきましょう。Vue.jsの場合、Vuexのインストールからになるのですが、Nuxt.jsの場合は標準でVuexが含まれているのですぐに使い始めることが出来ます。

Step1. モジュールファイルの作成

/storeディレクトリ内にモジュールファイルを作成します。
ここでもモーダルの表示制御を行うdispModalFlgを例に進めていきたいと思います。

// store/modal.js

// 【 State 】
export const state = () => ({
  // モーダルの表示制御フラグ
  dispModalFlg: false,
  // モーダルに表示される文言
  modalDetail: '',
})

// 【 Mutations 】
export const mutations = {
  // dispModalFlgのセッター
  setDispModalFlg(state, dispModalFlg) {
    state.dispModalFlg = dispModalFlg
  },
  // modalDetailのセッター
  setModalDetail(state, modalDetail) {
    state.modalDetail = modalDetail
  },
}

// 【 Actions 】
export const actions = {
  // モーダルを開く
  openModal({ commit }, { detail }) {
    // 非同期通信やその他の処理なんかもここに書く
    commit('setDispModalFlg', true)
    commit('setModalDetail', detail)
  },
}

Step2. コンポーネントからVuexにアクセス

コンポーネントから実際にVuexを使ってみたいと思います。
開くボタンを押せばモーダルが表示され、閉じるボタンを押せばモーダルが閉じるような動きを例に実装してみると以下のようなソースになります。

<template>
  <div>
    <!-- モーダル -->
    <div v-if="dispModalFlg">
      <p>{{ modalDetail }}</p>
      <!-- モーダル閉じるボタン -->
      <button @click="closeModal()" type="button">閉じる</button>
    </div>

    <!-- モーダル開くボタン -->
    <button @click="openModal()" type="button">開く</button>
  </div>
</template>

<script>
export default {
  computed: {
    dispModalFlg() {
      return this.$store.state.modal.dispModalFlg
    },
    modalDetail() {
      return this.$store.state.modal.modalDetail
    },
  },
  methods: {
    openModal() {
      this.$store.dispatch('modal/openModal', { detail: 'modal detail' })
    },
    closeModal() {
      this.$store.commit('modal/setDispModalFlg', false)
    },
  },
}
</script>

computed内でStateにて状態管理をしているdispModalFlgmodalDetailを取得しているのが分かると思います。
また、methods内ではopenModal()でActionを、closeModal()でMutationを実行していることが分かると思います。
このように記述することにより、どこからでもVuexにアクセス出来るようになります。

Vuexを使う上で役に立つTips

ヘルパー関数のすすめ

上のソースと全く同じ内容をヘルパー関数を使って書くとさらに簡潔に書けるのでおすすめです。

<template>
  <div>
    <!-- モーダル -->
    <div v-if="dispModalFlg">
      <p>{{ modalDetail }}</p>
      <!-- モーダル閉じるボタン -->
      <button @click="setDispModalFlg(false)" type="button">閉じる</button>
    </div>

    <!-- モーダル開くボタン -->
    <button @click="openModal({ detail: 'modal detail' })" type="button">開く</button>
  </div>
</template>

<script>
import { mapState, mapMutations, mapActions } from 'vuex'

export default {
  computed: {
    ...mapState('modal', ['dispModalFlg', 'modalDetail']),
  },
  methods: {
    ...mapActions('modal', ['openModal']),
    ...mapMutations('modal', ['setDispModalFlg']),
  },
}
</script>

ソースを見て分かる通り、computedmethodsにVuexのStateやMutations、Actionsを定義しておくことによって、そのまま@clickなどで使えるようになっています。

モジュール名をindex.jsにした場合

書き方が微妙に変わります。

// ファイル名がmodal.js
this.$store.dispatch('modal/openModal', { detail: 'modal detail' })

// ファイル名がindex.js
this.$store.dispatch('openModal', { detail: 'modal detail' })
// ファイル名がmodal.js
...mapState('modal', ['dispModalFlg', 'modalDetail']),

// ファイル名がindex.js
...mapState(['dispModalFlg', 'modalDetail']),

異なるモジュールにアクセス

とあるモジュールから別のモジュールにアクセスする場合、<モジュール名>/<関数名>で実行してもエラーになります。この場合、実行する際の第3引数に{ root: true }を渡してあげます。

// HogeモジュールのMutationsを実行する場合
export const actions = {
  sampleAction({ commit }, { detail }) {
    commit('hoge/hogeMethod', true, { root: true })
  },
}

さいごに

いかがだったでしょうか。
State、Mutation、Actionの意味と使い方さえ分かれば、そこまで難しくはないんじゃないかと個人的には思っています。まだストンと落とし切れてない人は公式サイトもあわせて見てみると、理解を深める助けになるかと思います。

モジュールをどの単位で分けるかや、どういったものをVuexで管理するかはそのときの設計によって変わってくるかと思いますが、うまく使えばアプリケーション開発をぐっと楽にしてくれるものなので、これを機にVuexを使い始めてくれたら幸いです。

それでは、今回はこのへんで。ではでは。


Category List カテゴリー

Tag List タグ