Async/Await not working for VueX getter but works for log











up vote
0
down vote

favorite












I have an object of convos with userIDs that I need to loop through and, inside the loop, I need to make a call to Firebase to get the corresponding userName and then return an object with the convos, userNames, and userIDs.



I have tried using the async/await and the result I get from console.log is correct but my return statement directly after that, is undefined. Why is this happening? They are receiving the same object.



store.js getter snippet



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









share|improve this question




















  • 2




    How do you know your function return undefined?
    – ittus
    Nov 9 at 5:42










  • I assume you think that getConvosObj will return convoObj? Because it doesn't return anything.
    – robertklep
    Nov 9 at 6:52






  • 1




    By design, getters are not meant to be asynchronous. As instead, they should return a certain store state and will be reactively updated when state changes. The fact, that code example above is quite hard to predict only proves that concept. Such approach also has performance flaws. Please, try to stick with original idea: calling actions -> changing state with mutations -> returning state with getters. This way flow is clear and debuggable.
    – aBiscuit
    Nov 9 at 6:54












  • Yes, I was trying to user the getConvosObj to return convoObj. I'm fairly new to Vue so I didn't remember that I shouldn't do asynchronous stuff in getters. I've restructured it the way sosmii suggested below and it works now. Thanks everyone!
    – MrSpinn
    Nov 9 at 16:35















up vote
0
down vote

favorite












I have an object of convos with userIDs that I need to loop through and, inside the loop, I need to make a call to Firebase to get the corresponding userName and then return an object with the convos, userNames, and userIDs.



I have tried using the async/await and the result I get from console.log is correct but my return statement directly after that, is undefined. Why is this happening? They are receiving the same object.



store.js getter snippet



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









share|improve this question




















  • 2




    How do you know your function return undefined?
    – ittus
    Nov 9 at 5:42










  • I assume you think that getConvosObj will return convoObj? Because it doesn't return anything.
    – robertklep
    Nov 9 at 6:52






  • 1




    By design, getters are not meant to be asynchronous. As instead, they should return a certain store state and will be reactively updated when state changes. The fact, that code example above is quite hard to predict only proves that concept. Such approach also has performance flaws. Please, try to stick with original idea: calling actions -> changing state with mutations -> returning state with getters. This way flow is clear and debuggable.
    – aBiscuit
    Nov 9 at 6:54












  • Yes, I was trying to user the getConvosObj to return convoObj. I'm fairly new to Vue so I didn't remember that I shouldn't do asynchronous stuff in getters. I've restructured it the way sosmii suggested below and it works now. Thanks everyone!
    – MrSpinn
    Nov 9 at 16:35













up vote
0
down vote

favorite









up vote
0
down vote

favorite











I have an object of convos with userIDs that I need to loop through and, inside the loop, I need to make a call to Firebase to get the corresponding userName and then return an object with the convos, userNames, and userIDs.



I have tried using the async/await and the result I get from console.log is correct but my return statement directly after that, is undefined. Why is this happening? They are receiving the same object.



store.js getter snippet



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









share|improve this question















I have an object of convos with userIDs that I need to loop through and, inside the loop, I need to make a call to Firebase to get the corresponding userName and then return an object with the convos, userNames, and userIDs.



I have tried using the async/await and the result I get from console.log is correct but my return statement directly after that, is undefined. Why is this happening? They are receiving the same object.



store.js getter snippet



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






javascript firebase vue.js async-await vuex






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 9 at 5:36

























asked Nov 9 at 5:21









MrSpinn

85




85








  • 2




    How do you know your function return undefined?
    – ittus
    Nov 9 at 5:42










  • I assume you think that getConvosObj will return convoObj? Because it doesn't return anything.
    – robertklep
    Nov 9 at 6:52






  • 1




    By design, getters are not meant to be asynchronous. As instead, they should return a certain store state and will be reactively updated when state changes. The fact, that code example above is quite hard to predict only proves that concept. Such approach also has performance flaws. Please, try to stick with original idea: calling actions -> changing state with mutations -> returning state with getters. This way flow is clear and debuggable.
    – aBiscuit
    Nov 9 at 6:54












  • Yes, I was trying to user the getConvosObj to return convoObj. I'm fairly new to Vue so I didn't remember that I shouldn't do asynchronous stuff in getters. I've restructured it the way sosmii suggested below and it works now. Thanks everyone!
    – MrSpinn
    Nov 9 at 16:35














  • 2




    How do you know your function return undefined?
    – ittus
    Nov 9 at 5:42










  • I assume you think that getConvosObj will return convoObj? Because it doesn't return anything.
    – robertklep
    Nov 9 at 6:52






  • 1




    By design, getters are not meant to be asynchronous. As instead, they should return a certain store state and will be reactively updated when state changes. The fact, that code example above is quite hard to predict only proves that concept. Such approach also has performance flaws. Please, try to stick with original idea: calling actions -> changing state with mutations -> returning state with getters. This way flow is clear and debuggable.
    – aBiscuit
    Nov 9 at 6:54












  • Yes, I was trying to user the getConvosObj to return convoObj. I'm fairly new to Vue so I didn't remember that I shouldn't do asynchronous stuff in getters. I've restructured it the way sosmii suggested below and it works now. Thanks everyone!
    – MrSpinn
    Nov 9 at 16:35








2




2




How do you know your function return undefined?
– ittus
Nov 9 at 5:42




How do you know your function return undefined?
– ittus
Nov 9 at 5:42












I assume you think that getConvosObj will return convoObj? Because it doesn't return anything.
– robertklep
Nov 9 at 6:52




I assume you think that getConvosObj will return convoObj? Because it doesn't return anything.
– robertklep
Nov 9 at 6:52




1




1




By design, getters are not meant to be asynchronous. As instead, they should return a certain store state and will be reactively updated when state changes. The fact, that code example above is quite hard to predict only proves that concept. Such approach also has performance flaws. Please, try to stick with original idea: calling actions -> changing state with mutations -> returning state with getters. This way flow is clear and debuggable.
– aBiscuit
Nov 9 at 6:54






By design, getters are not meant to be asynchronous. As instead, they should return a certain store state and will be reactively updated when state changes. The fact, that code example above is quite hard to predict only proves that concept. Such approach also has performance flaws. Please, try to stick with original idea: calling actions -> changing state with mutations -> returning state with getters. This way flow is clear and debuggable.
– aBiscuit
Nov 9 at 6:54














Yes, I was trying to user the getConvosObj to return convoObj. I'm fairly new to Vue so I didn't remember that I shouldn't do asynchronous stuff in getters. I've restructured it the way sosmii suggested below and it works now. Thanks everyone!
– MrSpinn
Nov 9 at 16:35




Yes, I was trying to user the getConvosObj to return convoObj. I'm fairly new to Vue so I didn't remember that I shouldn't do asynchronous stuff in getters. I've restructured it the way sosmii suggested below and it works now. Thanks everyone!
– MrSpinn
Nov 9 at 16:35












1 Answer
1






active

oldest

votes

















up vote
-1
down vote



accepted










Why is this happening ?



Because you called async function synchronously.

lets make your code simpler.



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

asyncFunction();
}


at this point, your getConvosObj() will return nothing, because getConvosObj() ends before asyncFunction() ends.

you need to wait until your asyncFunction() ends, then your code should be like this:



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

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


but you should not do like this, because getters are not meant to be asynchronous by design.

this may work, but you should try a different approach.



So what should you do ?



Use actions before using getters



this is a basic approach.



async functions should be in actions.

so your store should be like this:



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


then call your actions before using getter in your sample.vue:



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


wait for db and update store, then get its state.

doesnt make sense ?



Use vuexfire to connect your store directly to Realtime Database



another approach is this.



use vuexfire, then the state of the store is always up-to-date to realtime database, so you can call getters without calling actions.

i got tired to refactor / write a code, so google some sample if you wanna use that plugin :)



i refactored the original code a lot, so there should be some typo or mistake.

plz revise is if you find one.






share|improve this answer





















    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














     

    draft saved


    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53220270%2fasync-await-not-working-for-vuex-getter-but-works-for-log%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    -1
    down vote



    accepted










    Why is this happening ?



    Because you called async function synchronously.

    lets make your code simpler.



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

    asyncFunction();
    }


    at this point, your getConvosObj() will return nothing, because getConvosObj() ends before asyncFunction() ends.

    you need to wait until your asyncFunction() ends, then your code should be like this:



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

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


    but you should not do like this, because getters are not meant to be asynchronous by design.

    this may work, but you should try a different approach.



    So what should you do ?



    Use actions before using getters



    this is a basic approach.



    async functions should be in actions.

    so your store should be like this:



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


    then call your actions before using getter in your sample.vue:



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


    wait for db and update store, then get its state.

    doesnt make sense ?



    Use vuexfire to connect your store directly to Realtime Database



    another approach is this.



    use vuexfire, then the state of the store is always up-to-date to realtime database, so you can call getters without calling actions.

    i got tired to refactor / write a code, so google some sample if you wanna use that plugin :)



    i refactored the original code a lot, so there should be some typo or mistake.

    plz revise is if you find one.






    share|improve this answer

























      up vote
      -1
      down vote



      accepted










      Why is this happening ?



      Because you called async function synchronously.

      lets make your code simpler.



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

      asyncFunction();
      }


      at this point, your getConvosObj() will return nothing, because getConvosObj() ends before asyncFunction() ends.

      you need to wait until your asyncFunction() ends, then your code should be like this:



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

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


      but you should not do like this, because getters are not meant to be asynchronous by design.

      this may work, but you should try a different approach.



      So what should you do ?



      Use actions before using getters



      this is a basic approach.



      async functions should be in actions.

      so your store should be like this:



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


      then call your actions before using getter in your sample.vue:



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


      wait for db and update store, then get its state.

      doesnt make sense ?



      Use vuexfire to connect your store directly to Realtime Database



      another approach is this.



      use vuexfire, then the state of the store is always up-to-date to realtime database, so you can call getters without calling actions.

      i got tired to refactor / write a code, so google some sample if you wanna use that plugin :)



      i refactored the original code a lot, so there should be some typo or mistake.

      plz revise is if you find one.






      share|improve this answer























        up vote
        -1
        down vote



        accepted







        up vote
        -1
        down vote



        accepted






        Why is this happening ?



        Because you called async function synchronously.

        lets make your code simpler.



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

        asyncFunction();
        }


        at this point, your getConvosObj() will return nothing, because getConvosObj() ends before asyncFunction() ends.

        you need to wait until your asyncFunction() ends, then your code should be like this:



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

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


        but you should not do like this, because getters are not meant to be asynchronous by design.

        this may work, but you should try a different approach.



        So what should you do ?



        Use actions before using getters



        this is a basic approach.



        async functions should be in actions.

        so your store should be like this:



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


        then call your actions before using getter in your sample.vue:



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


        wait for db and update store, then get its state.

        doesnt make sense ?



        Use vuexfire to connect your store directly to Realtime Database



        another approach is this.



        use vuexfire, then the state of the store is always up-to-date to realtime database, so you can call getters without calling actions.

        i got tired to refactor / write a code, so google some sample if you wanna use that plugin :)



        i refactored the original code a lot, so there should be some typo or mistake.

        plz revise is if you find one.






        share|improve this answer












        Why is this happening ?



        Because you called async function synchronously.

        lets make your code simpler.



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

        asyncFunction();
        }


        at this point, your getConvosObj() will return nothing, because getConvosObj() ends before asyncFunction() ends.

        you need to wait until your asyncFunction() ends, then your code should be like this:



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

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


        but you should not do like this, because getters are not meant to be asynchronous by design.

        this may work, but you should try a different approach.



        So what should you do ?



        Use actions before using getters



        this is a basic approach.



        async functions should be in actions.

        so your store should be like this:



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


        then call your actions before using getter in your sample.vue:



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


        wait for db and update store, then get its state.

        doesnt make sense ?



        Use vuexfire to connect your store directly to Realtime Database



        another approach is this.



        use vuexfire, then the state of the store is always up-to-date to realtime database, so you can call getters without calling actions.

        i got tired to refactor / write a code, so google some sample if you wanna use that plugin :)



        i refactored the original code a lot, so there should be some typo or mistake.

        plz revise is if you find one.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 9 at 9:22









        sosmii

        1047




        1047






























             

            draft saved


            draft discarded



















































             


            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53220270%2fasync-await-not-working-for-vuex-getter-but-works-for-log%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Guess what letter conforming each word

            Port of Spain

            Run scheduled task as local user group (not BUILTIN)