bryken
bryken

Reputation: 167

Vuex action which returns a promise never resolves or rejects

I'm trying to build up my API service in my VueJS application by using Vuex. I'm in the process of refactoring some stuff to centralize error handling, clean-up, etc. The issue I'm running into is properly chaining Promises through my function calls.

At the root level, I have a BaseService class, which simply make API requests using AXIOS (not full class):

export abstract class BaseService {
  protected readonly API: AxiosInstance; // Full init left out

  protected deleteItem(url: string): Promise<any> {
    return new Promise((resolve, reject) => {
      this.API.delete(url)
        .then((response: any) => {
          resolve(response);
        })
        .catch((error: any) => {
          this.handleError(error); // Local function that logs error
          reject(error);
        });
    });
  }
}

Then I have one layer above which managers different features of the API by assembling the request URL and handling the data:

class CompanyService extends BaseService {
  private constructor() {
    super();
  }

  public delete(id: number): Promise<any> {
    return this.deleteItem(`${this.baseUrl}/api/companies/${id}`);
  }
}

Then in my Vuex action I'm calling the companyService delete function:

const action = {
  COMPANY_DELETE(context: any, id: number) {
    return new Promise((resolve, reject) => {
      companyService // Instance of CompanyService
        .delete(id)
        .then((response: any) => {
          console.log(response); // This logs successfully
          resolve(response);
        })
        .catch((error: any) => {
          console.log(error); // This logs successfully
          reject(error);
        });
    });
  }
};

The two console logs complete successfully as indicated by my comments. This issue comes in when I get to the component which invokes this action:

this.$store
  .dispatch("company/COMPANY_DELETE", company.id) // Namespaced
  .then((response: any) => {
    console.log(response); // Never gets called
  })
  .catch((error: any) => {
    console.log(error); // Never gets called
  });

Those two console logs are never called. What am I doing wrong here?

Upvotes: 2

Views: 4725

Answers (2)

bryken
bryken

Reputation: 167

What ended up working was to remove the extra Promise like Void Ray said. However, in my particular use-case I also need to support error propagation. So the below action contains the fixes that I needed to make.

const action = {
  COMPANY_DELETE(context: any, id: number) {
    return companyService // Instance of CompanyService
      .delete(id)
      .then((response: any) => {
        console.log(response);
      })
      .catch((error: any) => {
        console.log(error);
        throw error; // Needed to continue propagating the error
      });
  },
};

Upvotes: 3

Void Ray
Void Ray

Reputation: 10199

Small example to demonstrate an action with axios without an extra promise wrap...

const store = new Vuex.Store({
	state: {
  	followers: 0
  },
  mutations: {
  	updateFollowers(state, followers){
    	state.followers = followers;
    }
  },
  actions: {
    getFollowers({commit}) {
        return axios.get('https://api.github.com/users/octocat').then( (response) => {
        	commit("updateFollowers", response.data.followers);
          return "success!!!";
        });
    }
  }
})

Vue.component('followers', {
  template: '<div>Followers: {{ computedFollowers }}</div>',
  created () {
    this.$store.dispatch('getFollowers').then( (result) => {
    	console.log(result);
    });
  },
  computed: {
  	computedFollowers() {
    	return store.state.followers;
    }
  }
});

const app = new Vue({
	store,
  el: '#app'
})
<script src="https://unpkg.com/vue"></script>
<script src="https://unpkg.com/vuex"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<div id="app">
  <followers></followers>
</div>

Upvotes: 3

Related Questions