Nuxt.jsで理解するVuexのあんなことやこんなこと
Vuexを使うと様々な局面でアプリケーション開発の助けになります。複雑な状態管理を自作で実装する前にVuexの使い所と使い方を見ていきませんか?
はじめに
みなさんVuexをご存知ですか?
よほど簡易なアプリケーション開発でなければ必須級の機能になるVuex。
でも、Vuexってなんだか難しそうで尻込みしている人もまだまだたくさんいると思います。
今回はそんなVuexをNuxt.jsを使って理解していこうと思います。
まだNuxt.jsを使ったことがない人はこれを機にぜひNuxtデビューをしてみてください。きっと大好きになれる最高のフレームワークです。
Nuxtの始め方はこちら。
Vuexとは
まずはVuexについて。
VuexとはVueが用意してくれている状態管理ライブラリです。
上の図のように、Action、Mutationを使ってState(状態)を管理していきます。
Action、Mutation、Stateはどのコンポーネントからでもアクセス可能で、かつ状態の一元管理が可能なこともあり、便利に使えるデータストレージのような存在です。
Actionを実行することをdispatch(ディスパッチ)、Mutationを実行することをcommit(コミット) と呼ぶので覚えておいてください。
Vuexの使い所
上述したようにVuexは、
- どのコンポーネントからでもアクセス可能
- 状態の一元管理が可能
という特徴を持っています。
これらの特徴がどういった悩みや問題を解決してくれるか見ていきましょう。
ここではモーダルの表示制御を行う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にて状態管理をしているdispModalFlg
とmodalDetail
を取得しているのが分かると思います。
また、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>
ソースを見て分かる通り、computed
やmethods
に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を使い始めてくれたら幸いです。
それでは、今回はこのへんで。ではでは。