Search code examples
javascriptvue.jsgetter-settervuexvuex-modules

How to get value after mutation in Vuex?


I have simple Vuex module for global date object:

import moment from 'moment';

const state = {
    date: moment()
}

// getters
const getters = {
    date: state => state.date,
    daysInMonth: state => state.date.daysInMonth()
}

// mutations
const mutations = {
    subtractOneDay(state) {
        state.date.subtract(1, 'days');
    }
}

export default {
    state,
    getters,
    mutations
}

One of my child components:

import { mapGetters, mapMutations } from 'vuex';

export default {
    computed: Object.assign(mapGetters(['date', 'daysInMonth']), {}),
    methods: {
        subtractOneDay() {
            this.$store.commit('subtractOneDay');

            console.log(this.date.format('YYYY-MM-DD'), this.date.daysInMonth(), this.daysInMonth)
        }
    },
    created() {
        console.log('blocks created')
    },
    mounted() {
        console.log('blocks mounted')
    }
}

Basically I need to get days of month (29, 29, 30 or 31) when date is changed.

The problem is that computed property daysInMonth doesn't change...


Solution

  • Moment's subtract method mutates the referenced moment object. That is an issue for Vue, because it means the reference to state.date hasn't changed and the computed properties will not re-compute their value.

    You can work around this using moment's clone method to return a new moment in the subtractOneDay method.

    Here is an example.

    console.clear()
    
    const store = new Vuex.Store({
      state:{
        date: moment()
      },
      getters:{
        date: state => state.date,
        daysInMonth: state => state.date.daysInMonth()
      },
      mutations: {
        subtractOneDay(state) {
            state.date = state.date.clone().subtract(1, 'days');
        }
      }
    })
    
    new Vue({
      el: "#app",
      store,
      computed: Object.assign(Vuex.mapGetters(['date', 'daysInMonth']), {}),
      methods:{
        subtractOneDay(){
          this.$store.commit('subtractOneDay');
        }
      }
    })
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vuex/3.0.1/vuex.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.1/moment.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
    <div id="app">
      {{date}}
      <hr>
      {{daysInMonth}}
      <hr>
      <button @click="subtractOneDay">Subtract 1 Day</button>
    </div>