Returning Promises from Vuex actions

vuex action return value
vuex getters
vuex promise axios
vuex mapmutations
vuex dispatch from action
vuex action types
vue action returns promise
axios async vuex

I recently started migrating things from jQ to a more structured framework being VueJS, and I love it!

Conceptually, Vuex has been a bit of a paradigm shift for me, but I'm confident I know what its all about now, and totally get it! But there exist a few little grey areas, mostly from an implementation standpoint.

This one I feel is good by design, but don't know if it contradicts the Vuex cycle of uni-directional data flow.

Basically, is it considered good practice to return a promise(-like) object from an action? I treat these as async wrappers, with states of failure and the like, so seems like a good fit to return a promise. Contrarily mutators just change things, and are the pure structures within a store/module.


actions in Vuex are asynchronous. The only way to let the calling function (initiator of action) to know that an action is complete - is by returning a Promise and resolving it later.

Here is an example: myAction returns a Promise, makes a http call and resolves or rejects the Promise later - all asynchronously

actions: {
    myAction(context, data) {
        return new Promise((resolve, reject) => {
            // Do something here... lets say, a http call using vue-resource
            this.$http("/api/something").then(response => {
                // http success, call the mutator and change something in state
                resolve(response);  // Let the calling function know that http is done. You may send some data back
            }, error => {
                // http failed, let the calling function know that action did not work out
                reject(error);
            })
        })
    }
}

Now, when your Vue component initiates myAction, it will get this Promise object and can know whether it succeeded or not. Here is some sample code for the Vue component:

export default {
    mounted: function() {
        // This component just got created. Lets fetch some data here using an action
        this.$store.dispatch("myAction").then(response => {
            console.log("Got some data, now lets show something in this component")
        }, error => {
            console.error("Got nothing from server. Prompt user to check internet connection and try again")
        })
    }
}

As you can see above, it is highly beneficial for actions to return a Promise. Otherwise there is no way for the action initiator to know what is happening and when things are stable enough to show something on the user interface.

And a last note regarding mutators - as you rightly pointed out, they are synchronous. They change stuff in the state, and are usually called from actions. There is no need to mix Promises with mutators, as the actions handle that part.

Edit: My views on the Vuex cycle of uni-directional data flow:

If you access data like this.$store.state["your data key"] in your components, then the data flow is uni-directional.

The promise from action is only to let the component know that action is complete.

The component may either take data from promise resolve function in the above example (not uni-directional, therefore not recommended), or directly from $store.state["your data key"] which is unidirectional and follows the vuex data lifecycle.

The above paragraph assumes your mutator uses Vue.set(state, "your data key", http_data), once the http call is completed in your action.

Returning Promises from Vuex actions, The first thing to know is that store.dispatch can handle Promise returned by the triggered action handler and it also returns Promise: actions: { actionA ({ commit }​  Actions are often asynchronous, so how do we know when an action is done? And more importantly, how can we compose multiple actions together to handle more complex async flows? The first thing to know is that store.dispatch can handle Promise returned by the triggered action handler and it also returns Promise:


Just for an information on a closed topic: you don’t have to create a promise, axios returns one itself:

Ref: https://forum.vuejs.org/t/how-to-resolve-a-promise-object-in-a-vuex-action-and-redirect-to-another-route/18254/4

Example:

export const loginForm = ({commit},data) => {
        return axios.post('http://localhost:8000/api/login',data).then((response) => {
            console.log(response);
            commit('logUserIn',response.data.data);
        }).catch((error) => {
            commit('unAuthorisedUser',{
                error:error.response.data
            })
        })
};

Another example:

    addEmployee({ commit, state }) {       
        return insertEmployee(state.employee).then(result => {
            commit('setEmployee', result.data);
            return result.data // resolve 
        }).catch(err => {           
            throw err.response.data // reject
        });
    },

Actions, Let's create a Vuex action that updates user profile. actions: { UPDATE_PROFILE ({ commit, state }, { user }) { return new Promise((resolve, reject) => { As you can see UPDATE_PROFILE action returns a Promise. In Vuex actions are asynchronous, so the only way to know if the HTTP request succeeded or failed is to resolve or reject the promise. To let the calling function know that the HTTP call succeeded and see the response data we add the following code: resolve(response)


Actions

ADD_PRODUCT : (context,product) => {
  return Axios.post(uri, product).then((response) => {
    if (response.status === 'success') {  
      context.commit('SET_PRODUCT',response.data.data)
    }
    return response.data
  });
});

Component

this.$store.dispatch('ADD_PRODUCT',data).then((res) => {
  if (res.status === 'success') {
    // write your success actions here....
  } else {
     // write your error actions here...
  }
})

How to return a promise from Vuex action in Vue.js - Renat , Basically, is it considered good practice to return a promise(-like) object from an action? I treat these as async wrappers, with states of failure  In all my projects with vuex I used to call api methods in module's actions, store result in state and then handle result in component method by returning Promise like this: Component: { methods: { mapActions([ 'loadPages' ]), handleL


TL:DR; return promises from you actions only when necessary, but DRY chaining the same actions.

For a long time I also though that returning actions contradicts the Vuex cycle of uni-directional data flow.

But, there are EDGE CASES where returning a promise from your actions might be "necessary".

Imagine a situation where an action can be triggered from 2 different components, and each handles the failure case differently. In that case, one would need to pass the caller component as a parameter to set different flags in the store.

Dumb example

Page where the user can edit the username in navbar and in /profile page (which contains the navbar). Both trigger an action "change username", which is asynchronous. If the promise fails, the page should only display an error in the component the user was trying to change the username from.

Of course it is a dumb example, but I don't see a way to solve this issue without duplicating code and making the same call in 2 different actions.

How to return Promises from Vuex actions?, New Pattern Proposal: Return Promises in Vuex actions As pointed out in  I was expecting all three expects to succeed, since I understand that the .resolves() method makes the stub to return a resolved promise, and that would in turn trigger the next call under the then method on the component. But its not. How should I test that the Vuex actions are indeed called?


actions.js

const axios = require('axios');
const types = require('./types');

export const actions = {
  GET_CONTENT({commit}){
    axios.get(`${URL}`)
      .then(doc =>{
        const content = doc.data;
        commit(types.SET_CONTENT , content);
        setTimeout(() =>{
          commit(types.IS_LOADING , false);
        } , 1000);
      }).catch(err =>{
        console.log(err);
    });
  },
}

home.vue

<script>
  import {value , onCreated} from "vue-function-api";
  import {useState, useStore} from "@u3u/vue-hooks";

  export default {
    name: 'home',

    setup(){
      const store = useStore();
      const state = {
        ...useState(["content" , "isLoading"])
      };
      onCreated(() =>{
        store.value.dispatch("GET_CONTENT" );
      });

      return{
        ...state,
      }
    }
  };
</script>

New: Return Promises in Vuex actions (#54) · Issues · GitLab.org , vuex I used to call api methods in module's actions, store result in state and then handle result in component method by returning Promise  I have a Vue component, which is using a mapped action from a vuex store, which returns a promise. When the component calls the mapped action, and the mapped action is resolved, I am calling anothe


How to return promise from an action? · Issue #8 · vue-electron/vuex , I find that normal function (not async) in action return a Promise,is this a bug? actions: { actionA ({ commit }) { return 1; }) } } Then  If the action is to return the promise we strictly say that the promise handling from the component should not further call anything that may mutate state or call further actions. We allow thing like routing to be handled ect, as this is not always completely state driven.


Dispatch an action always return a Promise? · Issue #411 · vuejs/vuex, actions: { load(context) { return new Promise(( res, rej ) => { axios.get("/api/​customers") .then(result => { context.commit("setCustomers", result.data);  actions in Vuex are asynchronous. The only way to let the calling function (initiator of action) to know that an action is complete - is by returning a Promise and resolving it later.


Vuex and Asynchronicity, In this tutorial, you'll learn how to let the calling function know that the HTTP request succeeded or failed in Vue.js. Let's create a Vuex action  actions should never have real return values that your app relies on, their only side-effect should be mutations. If you rely on a sync return value, you are not following their intended use. Therefore, if they are sync but return a promise, that should not be a problem in any scenario. But why do we return a promise for every action?