Vuex公式ドキュメント
- Vuexの理解 ============
1.1 概要
- Vueアプリケーションにおける複数コンポーネント間で共有する状態を集中管理する仕組み
- state: アプリケーションのデータソース(データ)
- view: stateを宣言的にビューレイヤーにマッピング
- actions: ビューでのユーザー操作による状態変更を処理(複数の状態更新メソッドを含む)
1.2 複数コンポーネント間の状態共有問題の解決
- 同じ状態を複数のビューが依存している
- 異なるビューからの操作で同じ状態を変更したい
- 従来の解決方法
- 親コンポーネントにデータとその操作メソッドを定義
- 子コンポーネントにデータと操作メソッドを渡す(複数階層の渡し方が必要)
- Vuexはこの問題を解決するためのツール
- storeファイル構成 =============
- index.js:Vuexのメイン管理オブジェクトstoreのモジュール
- state.js:アプリケーションのデータソースとなる状態オブジェクト
- mutations.js:直接stateを更新するメソッド群を保持
- actions.js:commit経由でmutationを呼び出し、stateを更新するメソッド群
- getters.js:stateに基づく算出プロパティを保持
- mutation-types.js:mutationのタイプ名を定数として管理(任意)
2.1 状態管理の基本構造
- state:アプリケーションのデータソース
- view:stateを宣言的に表示
- actions:ビューからのイベントで状態を変更
2.1.1 state
Vuexが管理する状態オブジェクトで、唯一のデータソース
// アプリケーションのデータソース
const state = {
userName: 'Alice',
items: [
{
id: 1,
name: "Apple"
},
{
id: 2,
name: "Banana"
}
]
}
2.1.2 mutations
- **stateを直接変更するメソッド(コールバック)**を持つオブジェクト
- 呼び出し方法:
actionからcommit('mutation名')で呼び出す - 同期処理のみ許可、非同期リクエストは不可
const mutations = {
changeName (state, payload) {
// stateの特定プロパティを更新
state.userName = payload.newName
}
}
2.1.3 actions
- イベントハンドラを含むオブジェクト、非同期処理も可能
- 原理:
commit()によりmutationを実行してstateを更新 - 呼び出し方法:通常はコンポーネント内から
this.$store.dispatch('updateUser', newName)
const actions = {
updateUser ({commit, state}, newName) {
commit('changeName', {newName})
}
}
actionsとmutationsの違い
- Actionは直接stateを変更せず、Mutationを通じて変更する
- Actionは非同期処理を含められる
- Mutationは同期のみ、Actionは非同期も可能
2.1.4 getters
- **計算されたプロパティ(getter)**を持つオブジェクト
- 呼び出し方法:通常はコンポーネント内で
this.$store.getters.AAA
const getters = {
AAA (state) { return 'Hello' }
}
- Vuexの利用手順 ===========
インストール
npm install --save-dev vuex
3.1 index.jsの作成
Vuexのメイン管理オブジェクトの定義
import Vue from 'vue'
import Vuex from 'vuex'
import state from './state'
import mutations from './mutations'
import actions from './actions'
import getters from './getters'
import userModule from './user' // ユーザーモジュール
Vue.use(Vuex)
export default new Vuex.Store({
state,
mutations,
actions,
getters,
modules: {
userModule, // ユーザーモジュール
}
})
3.2 state.jsの作成
export default {
lat: 35.6895, // 緯度
lng: 139.6917, // 経度
location: {}, // 位置情報
categories: [], // カテゴリリスト
shops: [], // 店舗リスト
}
3.3 mutations.jsの作成
stateを直接更新するメソッド群
引数はオブジェクト形式
非同期処理は不可
import {
SET_LOCATION
} from './mutation-types'
export default {
// 位置情報を設定
[SET_LOCATION](state, payload) {
state.location = payload.location
}
}
3.4 actions.jsの作成
Mutationをcommitしてstateを更新するメソッド群
import {
SET_LOCATION
} from './mutation-types'
import {
fetchLocation
} from '../api/location'
export default {
// 位置情報を取得
async fetchLocationInfo ({commit, state}, params) {
const response = await fetchLocation(state.lat, state.lng)
const location = response.data
commit(SET_LOCATION, {location})
}
}
3.5 getters.jsの作成
stateに基づく計算プロパティ
export default {
// カート内の商品総数
totalItems(state) {
return state.cart.reduce((total, item) => {
return total + item.quantity
}, 0)
},
// 合計金額
totalPrice(state) {
return state.cart.reduce((total, item) => {
return total + item.price * item.quantity
}, 0)
}
}
3.6 mutation-types.jsの作成(任意)
mutationのタイプ定数を定義
export const INCREASE_COUNT = 'increase_count'
export const DECREASE_COUNT = 'decrease_count'
export const CLEAR_CART = 'clear_cart'
3.7 storeの設定
- 通常は
main.jsで行う - storeオブジェクトが登録されると、各コンポーネントに
$storeプロパティが追加される。主なプロパティは:
state: 登録されたstateオブジェクト
getters: 登録されたgettersオブジェクト
メソッド: dispatch(action名, データ): actionを実行
main.jsでの設定例:
import store from './store'
new Vue({
el: '#app',
render: h => h(App),
router,
store // storeオブジェクトの登録
})
3.8 コンポーネントでの使用
3.8.1 $storeオブジェクトの利用
メモ:module名は'users'とする
// actionsのメソッド呼び出し
this.$store.dispatch('addItem')
// モジュール管理の場合
this.$store.dispatch('users/addItem')
// stateの取得
this.$store.state.counter
// モジュール管理の場合
this.$store.state.users.counter
// gettersの取得
this.$store.getters.isEven
// モジュール管理の場合
this.$store.getters["users/isEven"]
3.8.2 map関数を利用したマッピング
インポート
import {mapState, mapGetters, mapActions} from 'vuex'
メソッドのマッピング
methods: {
...mapActions(['fetchLocation', 'fetchCategories']),
// モジュール管理の場合
...mapActions('users', ['fetchLocation', 'fetchCategories']),
}
stateのマッピング(computedで使用)
computed: {
...mapState(['counter', 'value']),
// モジュール管理の場合
...mapState('users', {
counter: state => state.counter,
value: state => state.value,
}),
}
gettersのマッピング(computedで使用)
computed: {
...mapGetters(['isEven']),
// モジュール管理の場合
...mapGetters('users', ['isEven'])
}
3.8.3 actionsの呼び出し
computedでmapStateまたはmapGettersを定義
// ...mapState(['location', 'categories']) はthis.$store.state.locationと同等
// ...mapGetters(['isEven']) はthis.$store.getters.isEvenと同等
呼び出し
mounted() {
// 位置情報の取得
this.fetchLocation()
// カテゴリ一覧の取得
this.fetchCategories()
}