Vuex 4 — Actions

John Au-Yeung - Jan 26 '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/

Vuex 4 is in beta and it’s subject to change.

Vuex is a popular state management library for Vue.

Vuex 4 is the version that’s made to work with Vue 3.

In this article, we’ll look at how to use Vuex 4 with Vue 3.

Actions

In Vuex 4, actions are similar to mutations.

The differences are that actions commit mutations and actions can have async operations.

To create an action, we can add an actions property to our store.

For instance, we can write:

<!DOCTYPE html>  
<html lang="en">  
  <head>  
    <script src="https://unpkg.com/vue@next"></script>  
    <script src="https://unpkg.com/vuex@4.0.0-beta.4/dist/vuex.global.js"></script>  
    <title>App</title>  
  </head>  
  <body>  
    <div id="app">  
      <button @click="increment">increment</button>  
      <p>{{count}}</p>  
    </div>  
    <script>  
      const store = new Vuex.Store({  
        state: {  
          count: 0  
        },  
        mutations: {  
          increment(state) {  
            state.count++;  
          }  
        },  
        actions: {  
          increment(context) {  
            context.commit("increment");  
          }  
        }  
      });  
      const app = Vue.createApp({  
        methods: {  
          increment() {  
            this.$store.dispatch("increment");  
          }  
        },  
        computed: {  
          count() {  
            return this.$store.state.count;  
          }  
        }  
      });  
      app.use(store);  
      app.mount("#app");  
    </script>  
  </body>  
</html>
Enter fullscreen mode Exit fullscreen mode

We created a Vuex store with an actions property that has the increment method in it.

It takes the comtext parameter with the commit method to commit mutations.

To dispatch the action in our component, we call this.$store.dispatch with the action name.

We can perform async operations in an action.

For example, we can write:

<!DOCTYPE html>  
<html lang="en">  
  <head>  
    <script src="https://unpkg.com/vue@next"></script>  
    <script src="https://unpkg.com/vuex@4.0.0-beta.4/dist/vuex.global.js"></script>  
    <title>App</title>  
  </head>  
  <body>  
    <div id="app">  
      <button @click="increment">increment</button>  
      <p>{{count}}</p>  
    </div>  
    <script>  
      const store = new Vuex.Store({  
        state: {  
          count: 0  
        },  
        mutations: {  
          increment(state) {  
            state.count++;  
          }  
        },  
        actions: {  
          incrementAsync({ commit }) {  
            setTimeout(() => {  
              commit("increment");  
            }, 1000);  
          }  
        }  
      });  
      const app = Vue.createApp({  
        methods: {  
          increment() {  
            this.$store.dispatch("incrementAsync");  
          }  
        },  
        computed: {  
          count() {  
            return this.$store.state.count;  
          }  
        }  
      });  
      app.use(store);  
      app.mount("#app");  
    </script>  
  </body>  
</html>
Enter fullscreen mode Exit fullscreen mode

We called commit inside the setTimeout callback to delay the action dispatch by a second.

Also, we can dispatch actions with a payload.

For instance, we can write:

<!DOCTYPE html>  
<html lang="en">  
  <head>  
    <script src="https://unpkg.com/vue@next"></script>  
    <script src="https://unpkg.com/vuex@4.0.0-beta.4/dist/vuex.global.js"></script>  
    <title>App</title>  
  </head>  
  <body>  
    <div id="app">  
      <button @click="increment">increment</button>  
      <p>{{count}}</p>  
    </div>  
    <script>  
      const store = new Vuex.Store({  
        state: {  
          count: 0  
        },  
        mutations: {  
          increment(state, payload) {  
            state.count += payload.amount;  
          }  
        },  
        actions: {  
          incrementAsync({ commit }, payload) {  
            setTimeout(() => {  
              commit("increment", payload);  
            }, 1000);  
          }  
        }  
      });  
      const app = Vue.createApp({  
        methods: {  
          increment() {  
            this.$store.dispatch("incrementAsync", { amount: 2 });  
          }  
        },  
        computed: {  
          count() {  
            return this.$store.state.count;  
          }  
        }  
      });  
      app.use(store);  
      app.mount("#app");  
    </script>  
  </body>  
</html>
Enter fullscreen mode Exit fullscreen mode

We added a payload parameter to the incrementAsync action to accept payloads in our action.

Then we pass in an object as the 2nd argument to the this.$store.dispatch method to dispatch our action.

We can also pass in an object with the type property and arbitrary properties that will be included in the payload:

<!DOCTYPE html>  
<html lang="en">  
  <head>  
    <script src="https://unpkg.com/vue@next"></script>  
    <script src="https://unpkg.com/vuex@4.0.0-beta.4/dist/vuex.global.js"></script>  
    <title>App</title>  
  </head>  
  <body>  
    <div id="app">  
      <button @click="increment">increment</button>  
      <p>{{count}}</p>  
    </div>  
    <script>  
      const store = new Vuex.Store({  
        state: {  
          count: 0  
        },  
        mutations: {  
          increment(state, payload) {  
            state.count += payload.amount;  
          }  
        },  
        actions: {  
          incrementAsync({ commit }, payload) {  
            setTimeout(() => {  
              commit("increment", payload);  
            }, 1000);  
          }  
        }  
      });  
      const app = Vue.createApp({  
        methods: {  
          increment() {  
            this.$store.dispatch({ type: "incrementAsync", amount: 2 });  
          }  
        },  
        computed: {  
          count() {  
            return this.$store.state.count;  
          }  
        }  
      });  
      app.use(store);  
      app.mount("#app");  
    </script>  
  </body>  
</html>
Enter fullscreen mode Exit fullscreen mode

The type is the name of the action and the other properties will end up in the payload object in the 2nd argument of the incrementAsync action.

Conclusion

We can create actions to commit mutations and run async code with Vuex 4.

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