Adding Mutations to a Vuex Store

John Au-Yeung - Jan 25 '21 - - Dev Community

Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62

Subscribe to my email list now at http://jauyeung.net/subscribe/

Vue.js is an easy to use web app framework that we can use to develop interactive front end apps.

With Vuex, we can store our Vue app’s state in a central location.

In this article, we’ll look at how to add mutations to a Vuex store so that we can update the store’s state and propagate the change to components that uses the store.

Adding Mutations

We can add a mutation by putting in a function that changes the state by taking it from the parameter and then mutating it.

For example, we can write the following code:

const store = new Vuex.Store({  
  state: {  
    count: 0  
  },  
  mutations: {  
    increase(state) {  
      state.count++;  
    }  
  }  
});
Enter fullscreen mode Exit fullscreen mode

Then we can run the mutation function by running:

store.commit('increase')
Enter fullscreen mode Exit fullscreen mode

Then state.count should go up by 1.

We can’t run mutation functions directly.

Commit with Payload

If we want to pass our own argument to it, we can add it after the state parameter, so we write:

const store = new Vuex.Store({  
  state: {  
    count: 0  
  },  
  mutations: {  
    increase(state, num) {  
      state.count += num;  
    }  
  }  
});
Enter fullscreen mode Exit fullscreen mode

Then we can commit the mutation by writing:

store.commit('increase', 10)
Enter fullscreen mode Exit fullscreen mode

Then state.count should go up by 10.

The second parameter is usually an object, so we can access property values by writing:

const store = new Vuex.Store({  
  state: {  
    count: 0  
  },  
  mutations: {  
    increase(state, payload) {  
      state.count += payload.amount;  
    }  
  }  
});
Enter fullscreen mode Exit fullscreen mode

Then we can commit the mutation by writing:

store.commit('increase', {  
  amount: 10  
})
Enter fullscreen mode Exit fullscreen mode

Any state changes will be observed by components automatically if they access the store from within it.

Vue’s reactivity rules like initializing initial state and using Vue.set to update objects, etc. all applies to Vuex stores.

We can replace strings for mutation names with constants by assigning them to constants.

For example, we can change the example we have above to:

const INCREASE = "increase";

const store = new Vuex.Store({  
  state: {  
    count: 1  
  },  
  mutations: {  
    [INCREASE](state, payload) {  
      state.count += payload.amount;  
    }  
  }  
});

store.commit(INCREASE, { amount: 10 });
Enter fullscreen mode Exit fullscreen mode

JavaScript since ES6 can have dynamic property names, so we can take advantage of that to replace names with constants.

Mutations Must Be Synchronous

Mutations must be synchronous because they’re untrackable since asynchronous code can be called at any time rather than line by line like synchronous code is.

Committing Mutations in Components

We can either use this.$store.commit to commit mutations or we can use Vuex’s helper methods to do so.

this.$store.commit

For example, we can use this.$store.commit as follows:

index.js :

const INCREASE = "increase";const store = new Vuex.Store({  
  state: {  
    count: 0  
  },  
  mutations: {  
    [INCREASE](state, payload) {  
      state.count += payload.amount;  
    }  
  }  
});

new Vue({  
  el: "#app",  
  store,  
  computed: Vuex.mapState(["count"]),  
  methods: {  
    increase(amount) {  
      this.$store.commit(INCREASE, { amount });  
    }  
  }  
});
Enter fullscreen mode Exit fullscreen mode

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://unpkg.com/vue/dist/vue.js"></script>  
    <script src="https://unpkg.com/vuex"></script>  
  </head>  
  <body>  
    <div id="app">  
      <button @click="increase(10)">Increase</button>  
      <p>{{count}}</p>  
    </div>  
    <script src="index.js"></script>  
  </body>  
</html>
Enter fullscreen mode Exit fullscreen mode

In the code above, we have the increase method as follows:

increase(amount) {  
  this.$store.commit(INCREASE, { amount });  
}
Enter fullscreen mode Exit fullscreen mode

This is called by our template when we click the Increase button.

this.$store.commit(INCREASE, { amount }); will increase state.count by the amount we pass in, which is 10.

Then we get the state back by using mapState so we can display it in our template.

When we click Increase, we get 10, 20, 30, etc.

mapMutations

We can use mapMutations to map mutations to methods in our component as follows:

index.js :

const INCREASE = "increase";

const store = new Vuex.Store({  
  state: {  
    count: 0  
  },  
  mutations: {  
    [INCREASE](state, payload) {  
      state.count += payload.amount;  
    }  
  }  
});

new Vue({  
  el: "#app",  
  store,  
  computed: Vuex.mapState(["count"]),  
  methods: {  
    ...Vuex.mapMutations([INCREASE])  
  }  
});
Enter fullscreen mode Exit fullscreen mode

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://unpkg.com/vue/dist/vue.js"></script>  
    <script src="https://unpkg.com/vuex"></script>  
  </head>  
  <body>  
    <div id="app">  
      <button @click="increase({amount: 10})">Increase</button>  
      <p>{{count}}</p>  
    </div>  
    <script src="index.js"></script>  
  </body>  
</html>
Enter fullscreen mode Exit fullscreen mode

In the code above, mapMutations maps the mutation methods to the component methods.

So:

...Vuex.mapMutations([INCREASE])
Enter fullscreen mode Exit fullscreen mode

maps the increase method adds an increase method to the component which calls this.$store.commit(INCREASE) .

INCREASE is the string 'increase' that we have in the first line.

In the template, we just called increase({amount: 10}) when the Increase button is clicked to update state.count in the store.

Conclusion

We add mutations to our Vuex store to update the state of our store.

To do this, we add methods under the mutations object.

Then we can call this.$store.commit or use mapMutations to map mutation methods in the store to component methods.

Mutations must be synchronous since they need to be trackable.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .