こんにちは、”はふぃ”です。

Vue.jsでFormなどを利用して動的に値が更新された場合、computedwatchを利用することでその変更を検知することができます。

では、storeの値が動的に変更された場合はどうでしょう?

今回はstoreのstateの値が動的に更新された場合にそれを検知する方法が何パターンかあるので説明します。

サンプルコード

ユーザーがFormで苗字名前を入力し、それを検知してstateにそれらの値をlastNamefirstNameとして保存するコードをサンプルとして利用します。

< 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>

gettersfullNameを参照して、氏名を表示できます。

store.watch

今度はstateの更新を検知し、pluginsなどVueを経由せずに次の処理を行う場合についてです。

この場合はstore.watchというstoreのインスタンスメソッドを利用します。

watch(fn: Function, callback: Function, options?: Object): Function

https://vuex.vuejs.org/ja/api/#watch

< 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

投稿者: はふぃ

若手のWEBフロントエンジニア。最近はバレーボールにハマってます!

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA