2

CONTEXT

I have two store modules : "Meetings" and "Demands". Within store "Demands" I have "getDemands" action, and within store "Meetings" I have "getMeetings" action. Prior to access meetings's data in Firestore, I need to know demands's Id (ex.: demands[i].id), so "getDemands" action must run and complete before "getMeetings" is dispatched.

Vuex documentation dispatching-action is very complete, but still, I don't see how to fit it in my code. There are also somme other good answered questions on the topic here :

I would like to know the best way to implement what I'm trying to accomplish. From my perspective this could be done by triggering one action from another, or using async / await, but I'm having trouble implementing it.

dashboard.vue

  computed: {
    demands() {
      return this.$store.state.demands.demands;
    },
    meetings() {
      return this.$store.state.meetings.meetings;
    }
  },
  created() {
    this.$store.dispatch("demands/getDemands");
   
    //this.$store.dispatch("meetings/getMeetings"); Try A : Didn't work, seems like "getMeetings" must be called once "getDemands" is completed
  },

VUEX store Module A – demands.js

export default {
  namespaced: true,
  state: {
    demands:[], //demands is an array of objects
  },
  actions: {

// Get demands from firestore     UPDATED

    async getDemands({ rootState, commit, dispatch }) {
      const { uid } = rootState.auth.user
      if (!uid) return Promise.reject('User is not logged in!')

      const userRef = db.collection('profiles').doc(uid)

      db.collection('demands')
        .where('toUser', "==", userRef)
        .get()
        .then(async snapshot => {
          const demands = await Promise.all(
            snapshot.docs.map(doc =>
              extractDataFromDemand({ id: doc.id, demand: doc.data() })
            )
          )
          commit('setDemands', { resource: 'demands', demands })
          console.log(demands)  //SECOND LOG
        })
      await dispatch("meetings/getMeetings", null, { root: true })    //UPDATE
    },

...

mutations: {
    setDemands(state, { resource, demands }) {
      state[resource] = demands
    },

...

Module B – meetings.js


export default {
  namespaced: true,
  state: {
    meetings:[],
  },
  actions: {

// Get meeting from firestore    UPDATED

getMeetings({ rootState, commit }) {
      const { uid } = rootState.auth.user
      if (!uid) return Promise.reject('User is not logged in!')

      const userRef = db.collection('profiles').doc(uid)

      const meetings = []

      db.collection('demands')
        .where('toUser', "==", userRef)
        .get()
        .then(async snapshot => {
          await snapshot.forEach((document) => {
            document.ref.collection("meetings").get()
              .then(async snapshot => {
                await snapshot.forEach((document) => {
                  console.log(document.id, " => ", document.data())  //LOG 3, 4
                  meetings.push(document.data())
                })
              })
          })
        })
      console.log(meetings)    // FIRST LOG
      commit('setMeetings', { resource: 'meetings', meetings })
    },

...

mutations: {
    setMeetings(state, { resource, meetings }) {
      state[resource] = meetings
    },
...
CharlesD89
  • 27
  • 1
  • 9
  • After `getDemands` receives its data and commits it, it should `return dispatch("meetings/getMeetings")`. This way, using `dispatch('demands/getDemands')` it's `.then()` will actually happen after `getMeetings` has finished whatever it's doing. As an alternative, you could declare `demands/getDemands` `async` and use `await` before dispatching `getMeetings`. This way returning `demands` will wait for `getMeetings`. A side note: you shouldn't `return` data from actions. You should commit it to `state` and components will get updated, since they use the state data. – tao Mar 07 '21 at 22:16
  • In `getMeetings`, the `for`-loop has a couple issues: (1) It returns after one iteration. You probably want to run the body for all `demands`, not just the first. If the body is async, you'd need to use `Promise.all` to accumulate `meetings`. (2) The *condition* expression has an assignment, but it should be a comparison. – tony19 Mar 08 '21 at 08:08
  • @tao @tony19 Thanks for the help, I have tried to implement the whole and remove the data returns, however I still can't quite figure out how to make sure to terminate `getDemands` before running `getMeetings`. I updated the code and add the logs order. – CharlesD89 Mar 09 '21 at 01:26

1 Answers1

0

Syntax:

dispatch(type: string, payload?: any, options?: Object): Promise<any

Make the call right

dispatch("meetings/getMeetings", null, {root:true})