Adding Actions to a Vuex Store
Tags: vue, webdev, programming, javascript
Published: 2021-01-26 01:16:18

**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 actions to our Vuex store to change the store’s state.

What are Actions?
=================

Actions are similar to mutations, but they commit mutations instead of mutating the state. Actions can also commit asynchronous operations unlike mutations.

For example, we can add a simple action as follows:

```
const store = new Vuex.Store({  
  state: {  
    count: 0  
  },  
  mutations: {  
    increase(state) {  
      state.count++;  
    }  
  },  
  actions: {  
    increase(context) {  
      context.commit("increase");  
    }  
  }  
});
```

An action takes a `context` object, which we can use to call `commit` to commit a mutation.

Dispatching Actions
===================

We can dispatch actions by calling `store.dispatch('increase')` .

It’s much more useful than commit mutations directly because we can run asynchronous operations with it.

For example, we can dispatch an action as follows in Vue app:

`index.js` :

```
const store = new Vuex.Store({  
  state: {  
    count: 0  
  },  
  mutations: {  
    increase(state, payload) {  
      state.count += payload.amount;  
    }  
  },  
  actions: {  
    increaseAsync({ commit }, payload) {  
      setTimeout(() => {  
        commit("increase", payload);  
      }, 1000);  
    }  
  }  
});

new Vue({  
  el: "#app",  
  store,  
  methods: {  
    ...Vuex.mapActions(["increaseAsync"])  
  },  
  computed: {  
    ...Vuex.mapState(["count"])  
  }  
});
```

`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="increaseAsync({amount: 10})">Increase</button>  
      <p>{{count}}</p>  
    </div>  
    <script src="index.js"></script>  
  </body>  
</html>
```

In the code above, we have the action `increaseAsync` with the following code:

```
increaseAsync({ commit }, payload) {  
  setTimeout(() => {  
    commit("increase", payload);  
  }, 1000);  
}
```

In the action method, we commit the `increase` mutation with a `payload` object that we pass in when we dispatch the action.

In the Vue instance, we have:

```
methods: {  
    ...Vuex.mapActions(["increaseAsync"])  
},  
computed: {  
  ...Vuex.mapState(["count"])  
}
```

which maps the actions in the store by calling `mapActions` , and added computed properties by mapping them from the store by using `mapState` so we get a `count` property which is computed from `state.count` as a computed property.

Then in the template, we call `increaseAsync` when we press the Increase button to update `state.count` after 1 second.

Finally, we should see the number updated since we mapped the state from the store.

Composing Actions
=================

We can chain actions that return promises.

For example, we can create an action to update 2 counts as follows:

`index.js` :

```
const store = new Vuex.Store({  
  state: {  
    count1: 0,  
    count2: 0  
  },  
  mutations: {  
    increase(state, payload) {  
      state.count1 += payload.amount;  
    },  
    decrease(state, payload) {  
      state.count2 -= payload.amount;  
    }  
  },  
  actions: {  
    async increaseAsync({ commit }, payload) {  
      return Promise.resolve(commit("increase", payload));  
    },  
    async decreaseAsync({ commit }, payload) {  
      return Promise.resolve(commit("decrease", payload));  
    },  
    async updateCounts({ dispatch }, payload) {  
      await dispatch("increaseAsync", payload);  
      await dispatch("decreaseAsync", payload);  
    }  
  }  
});

new Vue({  
  el: "#app",  
  store,  
  methods: {  
    ...Vuex.mapActions(["updateCounts"])  
  },  
  computed: {  
    ...Vuex.mapState(["count1", "count2"])  
  }  
});
```

`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="updateCounts({amount: 10})">Update Counts</button>  
      <p>Count 1: {{count1}}</p>  
      <p>Count 2: {{count2}}</p>  
    </div>  
    <script src="index.js"></script>  
  </body>  
</html>
```

In the code above, we have the `updateCounts` action switch calls `dispatch` with the `increaseAsync` action and `payload` . Then it calls `dispatch` with the `decreaseAsync` action and `payload` .

`increaseAsync` commits the `increase` mutation, and `decreaseAsync` commis the `decrease` mutation.

Since they all have `Promise.resolve` , they’re all async.

Then we include the `updateCounts` action from the store in our Vue instance with `mapActions` . And we also include the `count1` and `count2` states with `mapState` .

Then when we click the Update Counts button, we call `updateCounts` , and then `count1` and `count2` are updated as we click the button. `count1` should increase by 10 each time and `count2` should decrease by 10 each time we click it.

Conclusion
==========

We can use actions to commit one or more mutations or dispatch other actions.

It’s handy for grouping store operations together and running asynchronous code since mutations are always synchronous.

We can use `mapActions` to include them in our components.

Actions are dispatched by calling `dispatch` , while mutations are committed with the `commit` method.