Vuexの基本的な使い方(Vue. js v2)
Vuexについてと、Vue.js v2におけるVuexの基本的な使い方をまとめました。
Vuexとは
Vuexはライブラリ・ステイトマネジメントパターンです。
ステイトというのは状態と言われますが、ほぼデータのことと最初は思っていいです。
Vuexを使うことで、アプリのすべてのコンポーネントからアクセス可能な中心となるデータストア(保管場所)をつくることができます。
このストアは、「信頼できる唯一の情報源(SSOT:Single Source of Truth)」という概念に沿っています。
Vuexは、特に大きなアプリでたくさんのデータをシェアする場合に便利なので使われます。
もっとも大きな恩恵としては、events up props downが不要になることです。
Vuexのコアコンセプト
- state – データ、App-level state/data(ex. posts, users, todos)
- getters – stateもしくはcomputedされた値を取得
- actions – mutationをcommitしたときにコンポーネントから呼ばれる(async-awaitなど)
- mutations – state/dataを変更する(ex. データのアップデート)
- modules – それぞれのモジュールが自身のstate,getters, actions, mutationsを持つことができる(ex. todos module, auth module)
Vuexの基本的な使い方
Vuexを使わない場合状態からVuexを使った場合をみていきます。
まずVue createでVuexを選択するとstoreフォルダが作成されます。
その中に、index.jsが作成されています。
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
// dataにいれるものはstate
state: {
},
// computedにいれるものはgetters
getters: {
},
// methodsにいれるものはmutations、クリックイベントとか
mutations: {
},
// setTimeoutなど非同期的な処理の場合に使う
actions: {
},
modules: {
}
})
それぞれみていきます。
state
data()にいれていたものは、基本的にstateにいれます。
なにか製品のデータを扱うとします。
手順
- storeフォルダのindex.jsのstateに保管
- propsは不要になるので取り除く
- computed:{}を使う
- アクセスはthis.products.→this.$store.state.productsになる
- $storeを変数に格納してreturnすればsaleProductsのように使える
親コンポーネント
<!-- Vuexを使わない場合、子コンポーネントへ -->
<!-- <product-list-one v-bind:products="products"></product-list> -->
<!-- Vuexを使う場合、propsが不要なのでv-bindも不要 -->
<product-list-one></product-list>
import ProductListOne from './components/ProductListOne.vue'
export default {
name: 'app',
components: {
'product-list-one': ProductListOne
},
data() {
return {
// Vuexを使う場合はdataはstateに記述する
// products: [
// {name: '製品A', price: 250},
// {name: '製品B', price: 140},
// {name: '製品C', price: 360},
// {name: '製品D', price: 850}
// ]
}
},
上のdata()にいれているデータが不要になり、storeフォルダのindex.jsのstateに記述します。
index.js
export default new Vuex.Store({
// dataにいれるものはstate
state: {
products: [
{name: '製品A', price: 250},
{name: '製品B', price: 140},
{name: '製品C', price: 360},
{name: '製品D', price: 850}
]
},
})
子コンポーネント
<ul>
<li v-for="product in products">
<span class="name">{{product.name}}</span>
<span class="price">{{product.price}}円</span>
</li>
</ul>
export default {
// props:['products'],
computed: {
products() {
return this.$store.state.products
},
},
}
子コンポーネントでは、propsが不要になります。
代わりに、thisのあとに、$store.state.変数をcomputedをというしてアクセスします。
getters
computedにいれていたものはgettersに書きます。
index.js
// computedにいれるものはgetters
getters: {
saleProducts: state => {
const saleProducts = state.products.map(product => {
return {
name: product.name,
price: product.price / 4
}
})
return saleProducts
}
},
子コンポーネント
computed: {
...
saleProducts() {
return this.$store.getters.saleProducts
},
// スプレッド構文で使う
...mapGetters([
'saleProducts',
// 'example1',
// 'example2', ..といった具合に複数あっても一括にまとめられる
])
},
Vuex使って書く場合
- saleProducts(){}の中身をindex.jsのgetters:{}にいれる
- this.$storeはstore内では不要
- 上のようにgettersにアクセスしてreturnする
また、mapGettersを使って、複数あっても一括にまとめられるようになります。
mapActionsとmapGetters
Vuexのヘルパーと呼ばれるものです。
ヘルパーの種類
状態を呼び出す場合、
- mapState
- mapGetters
状態を変化させる場合、
- mapMutations
- mapActions
といったヘルパーがあります。
よくよく使われるのが、mapActionsとmapGettersです。
comuptedを使うなら、mapGettersを上のようにセットします。
actionsを使うときはmapActionsをセットします。
ヘルパーの使い方
- インポートする
- scriptに書く
- templateで使う
といったシンプルな手順です。
インポート
// importする
import {mapActions, mapGetters} from 'vuex'
scriptタグに書く
computed: {
saleProducts() {
...
},
// スプレッド構文で使う
...mapGetters([
'saleProducts',
...
])
},
...
methods: {
...
},
...mapActions([
'reducePrice',
])
}
...
templateタグ内で使う
<li v-for="product in saleProducts">
mutations
methodsにいれるもの(クリックイベントとか)はmutationsを使います。
setTimeoutなど、非同期処理などは使いません。
クリックされたと同時に積み上がるのでどの処理がどうなっているのはトラックできなくなるため。actionsを使います。
Vuexのmutationsを使う
- 下の内容をmutationsに移す
- this.$storeは取り除く
index.js
mutations: {
reducePrice: (state, payload) => {
// setTimeout(function() { setTimeoutはmutationsで使わない
state.products.forEach(product => {
product.price -= payload
})
// }, 3000)
}
},
子コンポーネント
methods: {
reducePrice: function (amount) {
this.$store.dispatch('reducePrice', amount)
},
actions 非同期の処理
setTimeoutを使ったり、axiosなどを使ってAPIを使うといった非同期の処理については、actionsを使います。
actionsはcontextを使います。
index.js
actions: {
reducePrice: (context, payload) => {
setTimeout(function() {
context.commit('reducePrice', payload)
}, 1500)
}
},
mapActionsはmethodsの中にセットします。
...
...mapActions([
'reducePrice',
])
...
ヘルパーを使うときは、基本的にスプレッド構文を使うと便利です。
modules
storeの中にmodulesフォルダを作成することで、モジュール単位に分割して状態管理をすることができます。
modulesの中にたとえばtodos.jsを作成します。
index.jsには次のように記述します。
index.js
import Vuex from 'vuex'
import Vue from 'vue'
import todos from './modules/todos'
// Load Vuex
Vue.use(Vuex)
// Create store
export default new Vuex.Store({
modules: {
todos
}
})
そして、todos.jsにstateなどを記述します。
todos.js
import axios from 'axios'
const state = {
todos: [],
}
const getters = {
}
const actions = {
}
const mutations = {
}
export default {
state,
getters,
actions,
mutations
}
axiosとvuexを使った基本的なCRUD操作方法を次の記事で紹介します。