3

Is it possible in VueX to make a method in mounted() wait until some mutation in other component is executed?

Because sometimes that mutation is executed before and sometimes after so therefore I would know if it would be possible to await after it runs when the component is mounted:

  mounted() {
    // await MutationName
    this.columnItemsInit();
  }
Alex T
  • 3,529
  • 12
  • 56
  • 105

3 Answers3

4

You can subscribe for mutations with the store.subscribe method

mounted() {
  let unsubscribe = null
  unsubscribe = this.$store.subscribe(({ type }) => {
    if (type === 'MutationName') {
      this.columnItemsInit()
      unsubscribe() // So it only reacts once.
    }
  })
}
emilrb
  • 129
  • 3
  • 2
    This is an interesting option but the problem here is that the mutation is sometimes executed before the component is mounted. In that case it would essentially never initialize. One possibility is to set a flag in the store to watch for and check. Maybe the state value itself could be watched by mapping it to a computed? Maybe the parent component should mediate and pass a prop indicating if the child component should initialize after the sibling component emits some kind of an even. Although it seems to me like rethinking the way this thing is set up in the first place is the best bet. – PeterTheLobster Apr 29 '20 at 21:50
  • True, I rarely have things being "inited" in my components. When something depends on a mutation happening, it usually becomes a computed property derived from whatever the mutation changes in the state. – emilrb May 02 '20 at 01:55
1

Unless the components are related somehow (Parent to child) it can be tricky. You could add a watcher to a computed property in your final component that looks at a value (named "alpha" for example) in the store which can be updated once the first component has finished it's function. So

Component 1

mounted() {
    // Run function then update state value "alpha" in store to say I am complete
}

Component 2

computed {
    valueInStore() {
        // return state value "alpha"
    }
},

watch: {
    valueInStore(value) {
        // If value "alpha" is complete run the following code
        this.columnItemsInit();
    }
}
Hides
  • 496
  • 1
  • 5
  • 15
0

The correct approach to do that is to use vuex actions. The nature of an action is to be asynchronous, so when you execute an action you can set an await for the action occur.

As stated by the documentation

Actions are similar to mutations, the differences being that:

  • Instead of mutating the state, actions commit mutations.
  • Actions can contain arbitrary asynchronous operations.

So you can await to that operation being performed before pass to the next operation.

As an example:

const store = new Vuex.Store({
    state: {
        token: null
    },
    mutations: {
        SET_TOKEN (state, payload) {
          state.token = payload
        }
      },
      actions: {
        SET_TOKEN ({ context }, token) {
          context.commit('SET_TOKEN', token)
        }
      }
})

After that in your methods/hooks is just call an action via dispatch method.

methods: {
    async refreshStoreValue() {
        await this.$store.dispatch('SET_TOKEN', token) //this will call an action declared in your store.
    }
}

You can use that statement inside a method declaration that is async, or inside your life cycle hooks (created, mounted, etc).

Danizavtz
  • 3,166
  • 4
  • 24
  • 25
  • They were asking about waiting for a mutation committed by another component to complete. There's also no reason to use an action if you only want to modify the state - mutation is sufficient. I'm pretty sure that using the await on a synchronous function with no async code also has virtually no effect. So this is essentially the same as committing a mutation but you've wrapped it in another function. – PeterTheLobster Apr 29 '20 at 21:42