VueJS Vuex - Promise that resolves on state change?
Asked Answered
P

2

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?

Precocity answered 6/10, 2018 at 14:25 Comment(2)
Who makes the asynchronous call? Can't you just immediately populate the variable with the promise?Artois
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...Precocity
P
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.

Pragmaticism answered 6/10, 2018 at 16:0 Comment(5)
I ended up simply polling as described in the answer to this: #30506460 But your solution does look interesting, I'll keep that in mind for next time!Precocity
@Precocity please be careful doing that for multiple values since it bypasses Vue's own reactivity system which is built for listening for changes.Pragmaticism
I understand, and I'm only using it outside of an actual vue component. But thanks for the warning.Precocity
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.Pragmaticism
You can also do exactly the same with Vuex watch. Just store instead of vm to watch and change vm.$watch with vm.watch.Urochrome
C
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();
        }
      });
    });
Culottes answered 22/12, 2020 at 14:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.