I'm fetching data from an external API via axios in the Vuex store, which gives me an array with objects - let's say - cities.
Each city has a zipCode, which I need to fetch city details with.
I want to add that details-object as a new key to the cities array.
Right now I'm fetching all cities and have another Vuex action to fetch the city details.
ACTION to fetch all cities
fetchCities: ({ commit, state, dispatch }) => {
let baseUrl = "https://my-url/cities";
let config = {
headers: {
accept: "application/json",
Authorization: ...
},
params: {
param1: "a",
param2: "b"
}
};
axios
.get(baseUrl, config)
.then(function(response) {
commit("UPDATE_CITIES_RAW", response.data.items);
})
.catch(function(error) {
console.log(error);
});
dispatch("fetchCityDetails");
},
MUTATION after fetching all cities
UPDATE_CITIES_RAW: (state, payload) => {
state.citiesRaw = payload;
},
Each object in that array has a zipCode, which I'm fetching details about this city with.
I tried to loop the citiesRaw array inside the action to fetch the details and commit a change for each iteration, but the array from the state is empty at this point, because the action gets called before the mutation.
ACTION to fetch city details
fetchCityDetails: ({ commit, state }) => {
let baseUrl = "https://my-url/cities/"
let config = {
headers: {
accept: "application/json",
Authorization: ...
}
};
// citiesRaw is empty at this point
state.citiesRaw.forEach(e => {
let url = baseUrl + e.zipCode;
axios
.get(url, config)
.then(function(response) {
commit("UPDATE_CITY_DETAILS", {
response: response.data,
zipCode: e.zipCode
});
})
.catch(function(error) {
console.log(error);
});
});
},
What are the best ways to wait for the first fetch and then update the array?
Should I even use the same array or create a new one to begin with?
Or is there even a better way to fetch based on fetched data in the Vuex store?
UPDATE
After fixing the dispatching before the async function even finished (thanks, @Y-Gherbi), I also refactored the way of fetching the details:
- Component dispatches
fetchCities - in
fetchCitiesaction: commitUPDATE_CITIES - in
UPDATE_CITIESmutation: .map on the payload and create new object -> push all tostate.cities - in
fetchCitiesaction: loopstate.cities& dispatchfetchCityDetails(zipCode)for each city - in
fetchCityDetailsaction: commitUPDATE_CITY_DETAILS - in
UPDATE_CITY_DETAILSmutation: .map onstate.citiesand addcityDetailsobject to the referred city object
new actions
fetchCities: ({ commit, state, dispatch }) => {
let baseUrl = "https://my-url/cities";
let config = {
headers: {
accept: "application/json",
Authorization: ...
},
params: {
param1: "a",
param2: "b"
}
};
let url = baseUrl;
axios
.get(url, config)
.then(function(response) {
commit("UPDATE_CITIES", response.data.items);
state.cities.forEach(city => {
dispatch("fetchCityDetails", city.zipCode);
});
}
})
.catch(function(error) {
console.log(error);
});
},
fetchCityDetails: ({ commit }, zipCode) => {
let baseUrl = "https://my-url/cities";
let config = {
headers: {
accept: "application/json",
Authorization: ...
},
};
let url = baseUrl + "/" + zipCode;
axios
.get(url, config)
.then(function(response) {
commit("UPDATE_CITY_DETAILS", {
cityDetails: response.data,
zipCode: zipCode
});
})
.catch(function(error) {
console.log(error);
});
}
new mutations
UPDATE_CITIES: (state, cities) => {
// I don't need all data & I want to rename the keys from the response,
// so I create a new object
cities = cities.map(city => {
let obj = {};
obj.zipCode = city.zip_code
obj.key1 = city.key_1;
obj.key2 = city.key_2;
return obj;
});
state.cities.push(...cities);
},
UPDATE_CITY_DETAILS: (state, payload) => {
let cities = state.cities;
// add one details-object for each city
cities = cities.map(city => {
if (city.zipCode == payload.zipCode) {
city.cityDetails = payload.cityDetails;
}
return city;
});
state.cities = cities;
}
The question remains: Is there a better/more optimized approach to this kind of fetching?