6

Is it possible to create a Promise that resolves once a variable in the global vuex store changes?

I have a variable that is initialized as null in the state store and will be populated via an asynchronous call.
A different part of the app is dependent on that variable being true or false and is supposed to wait while it is still null.

Is there a way to cleanly wait for the change of this variable?

TommyF
  • 6,660
  • 8
  • 37
  • 61
  • Who makes the asynchronous call? Can't you just immediately populate the variable with the promise? – Bergi Oct 06 '18 at 14:32
  • You mean put the promise itself in the global store? I haven't tried that yet but even if it would work, it doesn't quite feel right to me... Shouldn't the global state be in a defined state? I'd prefer to create a promise outside of it à la `while(state.foo == undefined) { wait(100); } resolve(state.foo)` but I don't know if that's possible and how to make that work... – TommyF Oct 06 '18 at 15:17

2 Answers2

10

You can vm.$watch on an expression or function and then wrap that with a promise.

function watch(vm, fn) {
  return new Promise(resolve => {
    const watcher = vm.$watch(fn, (newVal) => {
      resolve(newVal);
      watcher(); // cleanup;
    });
  });
}

This would let you do something like:

let change = await watch(vm, () => state.foo); // will resolve when state.foo changes

Inside an async function.

Note in general this isn't a terrific pattern and in most cases it is preferable and simpler to use a computed property (and not a promise) for this.

tony19
  • 125,647
  • 18
  • 229
  • 307
Benjamin Gruenbaum
  • 270,886
  • 87
  • 504
  • 504
  • I ended up simply polling as described in the answer to this: https://stackoverflow.com/questions/30505960/use-promise-to-wait-until-polled-condition-is-satisfied But your solution does look interesting, I'll keep that in mind for next time! – TommyF Oct 07 '18 at 09:33
  • @TommyF please be careful doing that for multiple values since it bypasses Vue's own reactivity system which is built for listening for changes. – Benjamin Gruenbaum Oct 07 '18 at 09:46
  • I understand, and I'm only using it outside of an actual vue component. But thanks for the warning. – TommyF Oct 07 '18 at 10:20
  • To be clear, I acknowledge there are cases where doing it with polling might be appropriate and easier. For example because even if you refactor vue out it'll continue to work. – Benjamin Gruenbaum Oct 07 '18 at 12:55
  • 1
    You can also do exactly the same with Vuex watch. Just store instead of vm to watch and change vm.$watch with vm.watch. – Marius Lian Feb 09 '23 at 10:50
1

Similar to Benjamin's answer and not exactly what you are asking for, just another option. Instead of watching state change you can subscribe to when a mutation of a specific type occurs and wrap that into a Promise.

new Promise(resolve => {
      let unsubscribeFn = this.$store.subscribe(mutation => {
        if (mutation.type === "MY_MUTATION") {
          unsubscribeFn();
          resolve();
        }
      });
    });
Kflexior
  • 297
  • 2
  • 9