Vuex: How to wait for action to finish?

Viewed 12972

I want to implement a login method. My code for it is :

login() {
  let user = {
    email: this.email,
    password: this.password
  };

  this.$store.dispatch('auth/login', user)
  console.log(this.$store.getters['auth/getAuthError'])
},

Where I reach the store and dispatch the login action.

the action in the store looks like this:

login(vuexContext, user) {
        return axios.post('http://localhost:8000/api/user/login', user)
        .then(res => {
            vuexContext.commit('setToken', res.data.token)
            vuexContext.commit('setUser', res.data, {root: true})
            localStorage.setItem('token', res.data.token)
            Cookie.set('token', res.data.token )
            this.$router.push('/')
        }).catch(err => {
            vuexContext.commit('setAuthError', err.response.data)
        })
    },

In the catch block, if an error happens, I update the state and set authError property to the error i get.

My problem is that, in the login method, the console.log statement is executed before the action is actually finished so that the authError property is the state has not been set yet. How to fix this issue ?

2 Answers

Your action is returning a promise so you can console after the promise has been resolved in then() block.

login() {
  let user = {
    email: this.email,
    password: this.password
  };

  this.$store.dispatch('auth/login', user).then(() => {
   console.log(this.$store.getters['auth/getAuthError'])
   // this.$router.push('/') // Also, its better to invoke router's method from a component than in a store file, anyway reference of a component may not be defined in the store file till you explicity pass it
  })
},

OR, you can make login an async function & wait for the action till promise returned by action has been resolved

async login() {
  let user = {
    email: this.email,
    password: this.password
  };

  await this.$store.dispatch('auth/login', user)
  console.log(this.$store.getters['auth/getAuthError'])
},

You can use async-await instead of Promise.then. But my suggestion is not to use Axios inside the store. Call Axios inside the login method and then call the store. Something like this:

methods: {
    async login() {
        try {
            const result = await axios.post('http://localhost:8000/api/user/login', this.user);
            this.$store.dispatch('auth/login', result);
        } catch (err) {
            console.log(err);
        }
    }
}

And then you just need to set the Object in your store.

Related