Vue.jsの学習過程で、vuexについて学んだ事、疑問、感じた事をまとめた記事になります。
私と同じようにVue(Vuex)初心者の方の少しでも参考になれば幸いです。
Vuexはいつ導入すべきなのか?
これは、私がVuexを学習し始めた頃に感じた疑問です。
シンプルなSPAを作成している場合、返ってコードが冗長になってしまって、導入するメリットがないのではないかと思いました。
公式ドキュメントには、こう書いてありました。
あなたが大規模な SPA を構築することなく、Vuex を導入した場合、冗長で恐ろしいと感じるかもしれません。そう感じることは全く普通です。あなたのアプリがシンプルであれば、Vuex なしで問題ないでしょう。
つまり、大規模なSPAを構築しないのであれば導入の恩恵を受けにくいという事です。
私はVuexの学習をする際に、node.jsのexpressで作ったAPIサーバーとVue.js(Vuex)を使ってシンプルなタスク管理アプリを作成しました。
この場合、シンプルなSPAなのでVuexの導入メリットはあまり無さそうだなと思いました。
しかし、ここで気をつけなければいけない事が一つありました。
今回作成するシンプルなタスク管理アプリは、一生シンプルなままなのかという事。
最初はシンプルでも、後から色々な機能を実装していき、複雑になっていくのではないか。そもそもそうじゃないと楽しくなくない?と感じました。
この辺りを考慮して、最初から導入しておくのが無難なのかなと感じました。
ある程度、形ができたアプリに状態管理を導入するのは、大変だと思うので。
Vuexで状態管理する範囲
Vuexには、state、mutations、actions、gettersがあり、storeのstateで状態管理をします。
私は、最初すべての状態をstoreのstateで管理しようとしていましたが、返って状態管理がしにくくなり、コードが冗長になってしまいました。
こちらも公式ドキュメントに書かれています。
Vuex を使うということは、全ての状態を Vuex の中に置くべき、というわけではありません。多くの状態を Vuex に置くことで、状態の変更がさらに明示的、デバッグ可能になりますが、ときにはコードを冗長でまわりくどいものにします。状態の一部がひとつのコンポーネントだけに属している場合は、それをローカルの状態として残しておくとよいでしょう。
つまり、コンポーネントをまたがないデータに関しては、無理にVuexで管理しないで、コンポーネントで管理すれば良いみたいですね。
Vuexでの状態管理
まず状態管理を行う為に、storeを作成します。
今回は、コンポーネントから受け取った値でstateのtextを更新するものとします。
import vue from 'vue'
import Vuex from 'Vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
text: ''
},
getters: {
todos(state) {
return state.text
}
},
mutations: {
setTodo(state, data) {
state.text = data
}
},
actions: {
updateTodos({ commit }, data) {
commit('setTodo', data)
}
}
})
getters
ゲッターは、主にstateのデータを表示したい時に使います。
gettersでstateを取得します。
getters: {
todos(state) {
return state.text
}
}
そしてコンポーネント側で、
computed: {
todos() {
this.$store.getters.todos
}
}
で呼び出す事ができます。
また、storeのgettersをコンポーネントのcomputedにマッピングするmapGetters
ヘルパーを使用して呼び出す事もできます。
import { mapGetters } from 'vuex'
computed: mapGetters([
'todos'
])
computed内で使用したい場合は、スプレッド演算子を使います。
computed: {
...mapGetters([
'todos'
])
}
このように、ヘルパーを使う事でコードがすっきりします。
mutations
値を受け取って、stateを書き換えるところ。mutations以外で値の更新を行なってはいけない。
mutationsは同期的でなければならい。
ミューテーションはcommit関数を使用して発火させます。
actions: {
updateTodos({ commit }, data) {
commit('setTodo', data)
}
}
この場合だと、actions内のcommit('setTodo', data)
の部分で発火させています。
第一引数に呼び出す関数名(タイプ)、第二引数にmutationsに渡したい値(ペイロード)を指定します。
mutations: {
setTodo(state, data) {
state.text = data
}
}
呼び出されたミューテーション側でも第二引数でペイロードを受け取ります。
コンポーネント内で、ミューテーションを呼び出すには、
methods: {
setTodo() {
this.$store.commit('setTodo')
}
}
で呼び出します。
ミューテーションもゲッター同様ヘルパーを使用する事もできます。
import { mapMutations } from 'vuex'
methods: mapMutations([
'setTodo'
])
actions
アクションでは、ミューテーションをコミットします。アクションは、非同期処理を行う事ができるのでAPIサーバーとの通信など非同期的な処理はアクション内で行う事になります。
actions: {
updateTodos({ commit }, data) {
commit('setTodo', data)
}
}
第二引数にコンポーネントから受け取った値を指定する事ができます。
コンポーネント内でアクションを呼び出すには、
methods: {
updateTodos() {
this.$store.dispatch('updateTodos')
}
}
で呼び出す事ができます。
また、store.dispatch
にマッピングするmapActions
ヘルパーを使用して呼び出す事もできます。
import { mapActions } from 'vuex'
export default {
methods: mapActions([
'updateTodos'
])
}
このようにして、コンポーネントから受け取った値をactions→mutations→stateと渡して行く事でVuexの一連の流れが完成します。
まとめ
今回は、Vuexの基本的な使い方について書きました。
私自身がまだ使いこなせていないので、徐々にSPAの規模を大きくしていきながら学び、また記事を書けたらたらと思っています。
Vue.jsは、公式ドキュメントがとても丁寧でわかりやすいので、本当に助かります。