【问题标题】:Vuex: Fetch data with axios based on already fetched dataVuex:根据已获取的数据使用 axios 获取数据
【发布时间】:2018-10-28 23:43:15
【问题描述】:

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

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

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

获取所有城市的操作

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

UPDATE_CITIES_RAW: (state, payload) => {
  state.citiesRaw = payload;
},

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

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

获取城市详细信息的操作

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 存储中获取的数据进行获取?

更新

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

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

新动作

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

新的突变

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

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

【问题讨论】:

  • 你能显示整个 vuex 存储代码吗?
  • @BoussadjraBrahim 您还需要什么?只有一个甚至没有执行的突变丢失了。
  • 我在尝试绑定你的代码 sn-ps 时掉线了,可能是因为我累了
  • 尝试将调度函数移到提交函数之后的下一行。数组 (citiesRaw) 为空,因为您在获取数据之前调用操作(因为 axios.get 是异步的)
  • 我在考虑更好的处理方法时遇到了一些问题。 1. 您是否需要在每个详细信息页面上同时只需要一个(或几个)所有城市详细信息或类似的东西? 2.后端提供多少个城市?有没有办法根据 userId 之类的东西来限制它?

标签: javascript vue.js vuejs2 axios vuex


【解决方案1】:

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

修复

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


替代解决方案

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

我个人会在用户实际需要这些数据时处理每个请求。在您的情况下,每当用户单击一行以展开它时。

将其存放在商店中?

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

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

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

您的商店可能如下所示:

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

很抱歉出现拼写错误和格式错误。在手机上输入代码太可怕了

【讨论】:

  • 与此同时,我正在考虑一种更优雅的方式来处理这个非常有趣的案例!
  • 谢谢,这有助于未定义的数组。仍然:我真的很想知道是否有更好的方法来做这样的事情。
  • 我用另一种解决方案更新了我的答案。你可以让它尽可能全面,但我希望这是一个好的开始
  • 非常感谢您的输入,但有一个问题:我在展开的行中显示了大部分详细信息,但详细信息中的一些数据实际上显示在该行(被点击),所以我迫切需要获取所有城市的所有详细信息,无论该行是否被点击。
  • 如果无法通过第一个请求从后端提供这些值,您可能需要采用第一种方法...
猜你喜欢
  • 2021-05-03
  • 2018-07-05
  • 2021-08-30
  • 1970-01-01
  • 1970-01-01
  • 2020-12-23
  • 2022-01-04
  • 2021-02-21
  • 2018-09-19
相关资源
最近更新 更多