javascript - Vuex:根据已获取的数据使用 axios 获取数据

标签 javascript vue.js vuejs2 axios vuex

我在 Vuex 存储中通过 axios 从外部 API 获取数据,这为我提供了一个包含对象的数组 - 比方说 - cities

每个 city 都有一个 zipCode,我需要用它来获取城市详细信息。 我想将该详细信息对象作为新键添加到 cities 数组。

现在我正在获取所有城市,并有另一个 Vuex 操作来获取城市详细信息。

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;
},

该数组中的每个对象都有一个 zipCode,我正在使用它获取有关该城市的详细信息。

我尝试在操作中循环 citiesRaw 数组以获取详细信息并为每次迭代提交更改,但此时状态数组为空 ,因为操作在突变之前被调用。

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);
      });
  });
},

等待第一次获取然后更新数组的最佳方法是什么?

我是应该使用同一个数组还是创建一个新数组?

或者是否有更好的方法来基于 Vuex 存储中获取的数据进行获取?

UPDATE

在异步函数完成之前修复调度之后(感谢@Y-Gherbi),我还重构了获取细节的方式:

  1. 组件调度 fetchCities
  2. fetchCities 操作中:提交 UPDATE_CITIES
  3. UPDATE_CITIES 突变中:.map 负载并创建新对象 -> 将所有内容推送到 state.cities
  4. fetchCities 操作中:循环 state.cities 并为每个城市分派(dispatch) fetchCityDetails(zipCode)
  5. fetchCityDetails 操作中:提交 UPDATE_CITY_DETAILS
  6. UPDATE_CITY_DETAILS 突变中:在 state.cities 上映射并将 cityDetails 对象添加到引用的城市对象

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;
}

问题仍然存在:对于这种抓取是否有更好/更优化的方法?

最佳答案

我认为有更好、更优雅的方法来处理这个问题,但只是为了帮助您解决这个错误(循环一个空数组,该数组应该是一个城市数组)

修复

尝试将调度函数移动到提交函数之后的下一行。 array (citiesRaw) 是空的,因为您在获取数据之前调用操作(因为 axios.get 是异步操作)


替代方案

如您所说,城市显示在具有可扩展行的表格中,用于显示城市详细信息。获取 100-1000 个城市是相当多的数据,但它仍然是对后端的一次调用。但是,从性能和带宽(如果这是大数据使用的正确术语)的 Angular 来看,遍历所有这些项目并为每个项目发出请求可能会出现问题。

就个人而言,只要用户实际需要此数据,我就会处理每个请求。在您的情况下,每当用户单击一行以将其展开时。

存放在商店里?

何时要在商店中存储城市详细信息由您决定。您可以将它保留在组件中,但就我个人而言,我会将其用作某种缓存机制。

当用户点击一行时,检查是否已经获取了详细信息

if(!state.cityDetails[key]) {
    axios.get()
        .then(res => {
            // Commit a mutation that saves the fetched details
        })
        .catch((error) => {
            // Handle error
        })
} else {
    // Use the 'cached' cityDetails
}

您的商店可能看起来像这样:

{
    cityDetails: {
        keyCouldBeIdOrZipcode: {...},
        anOtherAlreadyFetchedCity: {...},
    }
}

对于错别字和错误的格式,我们深表歉意。在手机上输入代码太可怕了

关于javascript - Vuex:根据已获取的数据使用 axios 获取数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53037066/

相关文章:

javascript - 在数组上使用递归

javascript - IE 和 Edge 中的 Mousewheel 和 dommousescroll 事件

javascript - 持续时间的移动用户界面

vue.js - Vue组件的结构应该是什么?应该按什么顺序添加功能?

javascript - 在 Vue 中使用组件声明数据

javascript - jQuery:模式表单在输入点击时不会提交

vue.js - Vuetify.js:单击时如何更改 v-btn 组件的颜色

javascript - Vue.js 内联模板错误

javascript - 如何将Html布局加载到vuejs组件中?

javascript - vue js 不更新模型