简体   繁体   中英

How to separate AXIOS requests from a Vuex store

I have a very normal Vuex store file and here is the code:

//store.js
import Vue from 'vue';
import Vuex from 'vuex';


Vue.use(Vuex);

export const store = new Vuex.Store({
  state: {
    loading: true,
    companyBasicInfo: [

    ]
  },
  mutations: {
    getCompanyBasicInfo: (state, res) => {
      state.companyBasicInfo.push(res);
    },
    changeLoadingStatue: (state, loading) => {
      state.loading = loading;
    }
  },
  actions: {
    getCompanyBasicInfo: context => {
// HERE IS MY AXIOS REQUESTS
    }
  }
});

I am writing my axios request in getCompanyBasicInfo() actions and everything works perfectly.

What I want to do

Separate my AXIOS requests in another file and just call them in my store.js file just to reduce my store.js file..

What I have tried

I have tried to create file called requests.js and write this code in it:

import axios from 'axios';

export default GET_COMPANY_DETAILS = () => {
  setTimeout(() => {
    axios.get('http://localhost:3000/companies/show/trade key egypt').then((res) => {
      context.commit('getCompanyBasicInfo', res.data);
      context.commit('changeLoadingStatue', false);
    }).catch(e => {
      console.log(e);
    });
  }, 3000);
};

And then trying to import them in my store.js file

import requests from './requests';

Problem

Whenever I try to write requests.GET_COMPANY_DETAILS(); in my getCompanyBasicInfo() action I couldn't access the method in the requests.js file.

ERROR I get

Uncaught ReferenceError: GET_COMPANY_DETAILS is not defined in console

Export problem

Since you're using export default GET_COMPANY_DETAILS , when you import requests , it is the GET_COMPANY_DETAILS function.

So you could call requests() directly.

See the MDN documentation on export to see all the possibilities.

How to export an API

That being said, the proper way to export an API would be:

// api.js
import axios from 'axios';

// create an axios instance with default options
const http = axios.create({ baseURL: 'http://localhost:3000/' });

export default {
    getCompanyDetails(tradeKey) {
        // then return the promise of the axios instance
        return http.get(`companies/show/${tradeKey}`)
            .catch(e => {
                // catch errors here if you want
                console.log(e);
            });
    },
    anotherEndpoint() {
        return http.get('other/endpoint');
    }
};

You can export a default API like I did, or even both named and default export.

export function getCompanyDetails(tradeKey){ /*...*/ }
export default { getCompanyDetails }

Then, in your store:

import api from './api';

// ...

actions: {
    getCompanyBasicInfo({ commit }, key) {
        // It's important to return the Promise in the action as well
        return api.getCompanyDetails(key).then(({ data }) => {
            commit('getCompanyBasicInfo', data);
            commit('changeLoadingStatue', false);
        });
    }
}

The store related code still needs to be within your actions.

Push the isolation a step further

I've written an answer with examples on axios-middleware and axios-resource which helps create single responsibility modules.

You can handle errors in a middleware, while focusing the endpoint configuration within resource classes.

I suggest you structure your code according to suggested application structure in Vuex documentation.

That will give you nice separation of concerns and make your store.js nice and lean.

Then, export the function instead of exporting it as default. In future, you may want to export multiple functions from requests.js .

Eg

import axios from 'axios';

export function getCompanyDetails() {
  setTimeout(() => {
    axios.get('http://localhost:3000/companies/show/trade key egypt').then((res) => {
      context.commit('getCompanyBasicInfo', res.data);
      context.commit('changeLoadingStatue', false);
    }).catch(e => {
      console.log(e);
    });
  }, 3000);
};

export function someOtherApiMethod() {}

Then, instead of using setTimeout in GET_COMPANY_DETAILS , return the promise from Axios itself.

Eg

 export function getCompanyDetails() {
    return axios
        .get('http://localhost:3000/companies/show/trade key egypt')
        .then(res => res.data)
};

Then, use the promise in your action

import { getCompanyDetails } from './requests';

actions: {
    getCompanyBasicInfo: context => {
        getCompanyDetails().then(() => {
            // commit your mutations
        });
    }
  }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM