Vuex: выборка данных с помощью аксиом на основе уже полученных данных - PullRequest
0 голосов
/ 29 октября 2018

Я извлекаю данные из внешнего API через axios в хранилище Vuex, которое дает мне массив с объектами - скажем, 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. in fetchCities action: commit UPDATE_CITIES
  3. in UPDATE_CITIES mutation: .map в полезной нагрузке и создание нового объекта -> подтолкнуть все к state.cities
  4. infetchCities action: loop state.cities & dispatch fetchCityDetails(zipCode) для каждого города
  5. in fetchCityDetails action: commit UPDATE_CITY_DETAILS
  6. in 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;
}

Остается вопрос: есть ли лучший / более оптимизированный подход к такому извлечению?

1 Ответ

0 голосов
/ 29 октября 2018

Я думаю, что есть намного лучшие и изящные способы справиться с этим, но просто помочь вам с ошибкой (зацикливание на пустом массиве, который, как ожидается, будет массивом городов)

исправление

Попробуйте переместить функцию отправки на следующую строку после функции фиксации. 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': {...}
    }
}

извините за опечатки и плохое форматирование. Ввод кода на телефоне ужасен

...