こんにちは、”はふぃ”です。
Vue.jsでFormなどを利用して動的に値が更新された場合、computed
やwatch
を利用することでその変更を検知することができます。
では、storeの値が動的に変更された場合はどうでしょう?
今回はstoreのstateの値が動的に更新された場合にそれを検知する方法が何パターンかあるので説明します。
目次
サンプルコード
ユーザーがFormで苗字と名前を入力し、それを検知してstateにそれらの値をlastName
とfirstName
として保存するコードをサンプルとして利用します。
< components/pages/sample/StoreWatchPage.vue >
<template>
<div>
<div>苗字:<input v-model="lastName"></div>
<div>名前:<input v-model="firstName"></div>
</div>
</template>
<script>
import { mapMutations } from 'vuex'
export default {
data () {
return {
lastName: '',
firstName: ''
}
},
watch: {
lastName (val) {
this.setLastName(val)
},
firstName (val) {
this.setFirstName(val)
}
},
methods: {
...mapMutations('sample/storeWatch', [
'setLastName',
'setFirstName'
])
}
}
</script>
< store/sample/storeWatch/mutations.js >
export function setLastName(state, val) {
state.lastName = val
console.log(`setLastName is done. val is 「${val}」`)
}
export function setFirstName(state, val) {
state.firstName = val
console.log(`setFirstName is done. val is 「${val}」`)
}
< store/sample/storeWatch/state.js >
export default () => ({
lastName: '',
firstName: ''
})
この状態で実行し、氏名を入力すると以下のようにmutations
が実行されたことがわかります。

stateの更新を検知する方法
getters
state
の更新を検知し、その値を参照したい場合はgetters
を利用します。
< store/sample/storeWatch/getters.js >
export function fullName (state) {
const { lastName, firstName } = state
return `${lastName} ${firstName}`
}
< components/pages/sample/StoreWatchPage.vue >
<template>
<div>
<div>苗字:<input v-model="lastName"></div>
<div>名前:<input v-model="firstName"></div>
<div>氏名は「{{ fullName }}」です。</div>
</div>
</template>
<script>
import { mapMutations, mapGetters } from 'vuex'
export default {
data () {
return {
lastName: '',
firstName: ''
}
},
computed: {
...mapGetters('sample/storeWatch', [
'fullName'
])
},
watch: {
lastName (val) {
this.setLastName(val)
},
firstName (val) {
this.setFirstName(val)
}
},
methods: {
...mapMutations('sample/storeWatch', [
'setLastName',
'setFirstName'
])
}
}
</script>
getters
のfullName
を参照して、氏名を表示できます。

store.watch
今度はstateの更新を検知し、plugins
などVueを経由せずに次の処理を行う場合についてです。
この場合はstore.watch
というstoreのインスタンスメソッドを利用します。
https://vuex.vuejs.org/ja/api/#watch
watch(fn: Function, callback: Function, options?: Object): Function
< plugins/storeWatchPlugin.js >
export default function storeWatchPlugin ({ store }) {
store.watch(state => {
const { lastName, firstName } = state.sample.storeWatch
return `${lastName} ${firstName}`
}, val => {
store.commit('sample/storeWatch/setFullName', val)
})
}
< store/sample/storeWatch/mutations.js >
export function setLastName(state, val) {
state.lastName = val
}
export function setFirstName(state, val) {
state.firstName = val
}
export function setFullName(state, val) {
state.fullName = val
}
< store/sample/storeWatch/state.js >
export default () => ({
lastName: '',
firstName: '',
fullName: ''
})
< components/pages/sample/StoreWatchPage.vue >
<template>
<div>
<div>苗字:<input v-model="lastName"></div>
<div>名前:<input v-model="firstName"></div>
<div>氏名は「{{ fullName }}」です。</div>
</div>
</template>
<script>
import { mapMutations, mapState } from 'vuex'
export default {
data () {
return {
lastName: '',
firstName: ''
}
},
computed: {
...mapState('sample/storeWatch', [
'fullName'
])
},
watch: {
lastName (val) {
this.setLastName(val)
},
firstName (val) {
this.setFirstName(val)
}
},
methods: {
...mapMutations('sample/storeWatch', [
'setLastName',
'setFirstName'
])
}
}
</script>
今度のパターンでは、stateの更新をplugins
内のstore.state
が検知し、次の処理であるstore.commit
を実行することでstateのfullName
を更新しています。そのため、結果としてはgettersの時と同様となります。

まとめ
頻繁に使うのはgettersの方だと思いますが、Vueを経由しない方法は覚えておくとたまに使うことがあるので便利です!
参考
今回のコードはgithubで公開中なので参考にしてみてください!↓
https://github.com/hafilog/vue-sample/tree/master/components/pages/sample