Async / Await не работает для геттера VueX, но работает для журнала - PullRequest
0 голосов
/ 09 ноября 2018

У меня есть объект конвоев с userIDs , который мне нужно пройти через цикл, и внутри цикла мне нужно сделать вызов Firebase, чтобы получить соответствующее userName , а затем вернуть объект с именами конвой, userNames и userID.

Я попытался использовать async / await, и результат, который я получаю из console.log, верен, но мой оператор return сразу после этого не определен. Почему это происходит? Они получают один и тот же объект.

store.js фрагмент геттера

getConvosObj: state => {
  var convoObj = {};
  var userConvos = state.userProfile.convos;
  async function asyncFunction() {
    for (const key in userConvos) {
      if (userConvos.hasOwnProperty(key)) {
        const userID = userConvos[key];
        var userName;
        await fire.database().ref('/users/' + userID + '/userName').once('value', async (snapshot) => {
          userName = await snapshot.val();
          convoObj[key] = {userName, userID}
        })
      }
    }
    console.log(convoObj);   //result: correct object
    return convoObj;         //result: undefined
  }
  asyncFunction();
}

1 Ответ

0 голосов
/ 09 ноября 2018

Почему это происходит?

Поскольку вы вызвали асинхронную функцию синхронно.
давайте сделаем ваш код проще.

getConvosObj: state => {
    async function asyncFunction() {
        // ...
    }

    asyncFunction();
}

в этот момент ваш getConvosObj() вернет ничего , потому что getConvosObj() заканчивается до asyncFunction().
вам нужно дождаться окончания вашего asyncFunction(), тогда ваш код должен выглядеть так:

getConvosObj: async state => { // <- changed here
  async function asyncFunction() {
    // ...
  }

  await asyncFunction(); // <- changed here too
}

но вы не должны делать это , потому что геттеры не предназначены для асинхронного проектирования.
это может сработать, но вы должны попробовать другой подход.

Так что же вам делать?

Используйте действия перед использованием геттеров

это базовый подход.

асинхронные функции должны быть в действиях.
поэтому ваш магазин должен быть таким:

export default () => 
  new Vuex.Store({
    state: {
      convoObj: null
    },
    mutations: {
      updateConvoObj(state, payload) {
        state.convoObj = payload;
      }
    },
    actions: {
      async fetchAndUpdateConvoObj({ state, commit }) {
        const fetchUserData = async userId => {
          const snapShot = await fire.database().ref('/users/' + userID + '/userName').once('value');
          const userName = snapShot.val();

          return {
            userName: userName,
            userID: userId
          }
        }

        const userConvos = state.userProfile.convos;

        let convoObj = {};
        for (const key in userConvos) {
          if (userConvos.hasOwnProperty(key)) {
            const userId = userConvos[key];
            const result = await fetchUserData(userId);

            convoObj[key] = {
              userName: result.userName,
              userId: result.userId
            }
          }
        }

        commit('updateConvoObj', convoObj);
      }
    }
  });

затем вызовите свои действия перед использованием getter в вашем sample.vue:

await this.$store.dispatch('fetchAndUpdateConvoObj');
convoObj = this.$store.getters('getConvoObj');

дождитесь БД и обновите хранилище, затем получите его состояние.
не имеет смысла?

Используйте vuexfire, чтобы напрямую подключить ваш магазин к базе данных реального времени

другой подход заключается в следующем.

используйте vuexfire, тогда состояние хранилища всегда актуально для базы данных в реальном времени, поэтому вы можете вызывать получатели без вызова действий.
я устал реорганизовывать / писать код, так что гуглите пример, если вы хотите использовать этот плагин:)

Я многократно переработал исходный код, поэтому должна быть какая-то опечатка или ошибка.
Пересмотрите, пожалуйста, если вы его найдете.

...