Vue, await for Watch
Asked Answered
D

3

11

i have similar architecture in my app.

computed(){ 
   someStoreValue = this.$store.someStoreValue; 
}
watch() { 
   someStoreValue() = async function () { 
    //do some async action 
   
   }
}, 
methods: { 
  someAction() {        
     this.$store.someStoreValue = 'NEW VALUE'     
     //await for "watch" 

     //do stuff

  }
}

I need to "someAction" await for "someStoreValue" watcher ends. I need this kind of architecture someStoreValue can be changed in many places.

Devanagari answered 31/7, 2020 at 8:33 Comment(0)
B
19

Sure, you can't make your watchers async, which is pretty senseless since the data you are after has already arrived.

someStoreValue(newValue, oldValue) { 
    // But you can still call other async functions. 
    // Async functions are just functions that returns a promise. Thus:
    doSomeAsyncAction().then(this.someAction)
}

Still, why not just do your async stuff in someAction instead?

watch:{ 
    someStoreValue(newValue, oldValue) { 
        this.someAction()
    }
},
methods:{
    async someAction(){
        await doSomeAsyncStuff() // What prevents you from doing this?
        //do stuff
    }
}
Bestiary answered 31/7, 2020 at 8:50 Comment(6)
The thing is that once you make the someAction method asynchronous, you have to await this.someAction` method call and you will be forced to use the async keyword on the watch. I don't imagine there would be any problems doing that.Gail
The first example uses a .then chain, no need for await. The second puts all the waiting in methods and no need to make watch async, which is impossible anyway.Bestiary
True. I just saw that. However, the use of .then and async-await doesn't help with consistency, won't you say? It works, but it just rubs me some kinda way.Gail
Yes, I would also prefer to stick to one syntax.Bestiary
this.someAction() is an async method and you are forced to write async keyword on this.someAction() inside watch which again throws errors and I find the solution not useful.Rodriquez
why can't make the watchers async? I thought you can do watch:{ async someStoreValue(newValue, oldValue) { ?Coryza
O
3

You can use a flag and wait for it.

data() {
   return {
      flag: false
   }
},
watch() { 
   someStoreValue() = async function () { 
    //do some async action 
  
     flag = true;  
   }
}, 
methods: { 
  async someAction() {        
     this.$store.someStoreValue = 'NEW VALUE'     
     await new Promise((resolve) => {
       if (this.flag) {
         resolve();
       } else {
         const unwatch = this.$watch('flag', (newVal) => {
           if (newVal) {
             unwatch();
             resolve();
           }
         });
       }
      });

     //do stuff

  }
}

Maybe in this case the @ippi solution is better, but you can use this approach in other cases.

Oneiromancy answered 19/11, 2020 at 7:58 Comment(0)
S
0

This is related, but maybe not exactly answering the question.

I wanted to perform an action once per created but I wanted to wait on a value being loaded by Vuex (triggered by another component). Here's what I came up with.

// outside of component
//   this is to avoid race condition of the eager watcher
let resolve: Function;
const promise = new Promise((res: Function) => {
  resolve = res;
});


// inside component
created() {
  promise.then(this.someAction);
},
watch: {
  someValueToWatch: {
    handler(val) {
      if (val) resolve();
    },
    immediate: true,
  },
},
methods: {
  someAction() {
     // do something once per created/mounted only after someValueToWatch is loaded
  },
},

Seasonal answered 6/3, 2024 at 23:23 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.