'Vue - How to access component's property from Vuex

In my app I use Vuex to perform async tasks. In this case I use it to log user to my app. When user is logged and axios.then() is being performed I want to inform the component from which I called this.$store.dispatch('login', {username: userObj.username, password: userObj.password}); My component:


    data() {
        test: false
    },

    methods: {

        login() {
            const userObj = {
                username: this.username,
                password: this.password
            };
            console.log(userObj);
            this.$store.dispatch('login',
                {
                    username: userObj.username, password: userObj.password
                });
        }
    },

Vuex:

const actions = {
    login({ commit }, authData) {
        axios.post('/login', {
            username: authData.username,
            password: authData.password
        })
            .then(resp => {
                console.log(resp);
                localStorage.setItem('token', resp.data.authToken);
                localStorage.setItem('userId', resp.data.id);
                localStorage.setItem('user', resp.data);
                commit('storeUser', resp.data);
                router.replace('/dashboard');
            })
            .catch(e => {
                console.log(e);
                alert('Something went wrong, try again')
            });
    },
}

Here, in .then() method I want somehow to change test property in my component to true. Can someone help me with this one?



Solution 1:[1]

You can return a Promise from a vuex action:

const actions = {
    login({ commit }, authData) {
        return new Promise((resolve, reject) => {
            axios.post('/login', {
                username: authData.username,
                password: authData.password
            })
                .then(resp => {
                    console.log(resp);
                    localStorage.setItem('token', resp.data.authToken);
                    localStorage.setItem('userId', resp.data.id);
                    localStorage.setItem('user', resp.data);
                    commit('storeUser', resp.data);
                    router.replace('/dashboard');
                    resolve(resp);
                })
                .catch(e => {
                    console.log(e);
                    alert('Something went wrong, try again')
                    reject(e);
                });
        })
    },
}

When you dispatch the action you can just treat it like a Promise (because the return value is a Promise):

// inside your component
this.
  $store.
  dispatch('login', {username: userObj.username, password: userObj.password})
  .then(resp => { /* do something with axios response using component data and methods*/);

Solution 2:[2]

The whole point of having the Vuex store is not to change your component props/data. Instead, you are supposed to store the data in Vuex and listen to the changes/updates in the component. So, in your login action, you should have something like:

// Commit the changes to the store
commit('storeTest', true);

and then, in the component:

computed: {
    // Get the value from the store
    test: () => {
        return this.$store.test;
    }
},

Solution 3:[3]

Vuex actions are thennable, so basically your action dispatch in the component should look something like this:

this.$store.dispatch('login', { username: userObj.username, password: userObj.password }).then(res => {
// response handling
});

Also your action must return the response in order for it to work.

const actions = {
    login({ commit }, authData) {
        axios.post('/login', {
            username: authData.username,
            password: authData.password
        })
            .then(resp => {
                console.log(resp);
                localStorage.setItem('token', resp.data.authToken);
                localStorage.setItem('userId', resp.data.id);
                localStorage.setItem('user', resp.data);
                commit('storeUser', resp.data);
                router.replace('/dashboard');
                return resp
            })
            .catch(e => {
                console.log(e);
                alert('Something went wrong, try again')
            });
    },
}

Solution 4:[4]

For mutations ??u can use subscribe or subscribeAction for actions as such:

mounted() {
    this.$store.subscribeAction({
        before: (action, state) => {
            switch (action.type) {
                case 'login':
                    this.test = false;
                    break;
            }
        },
        after: (action, state) => {
            switch (action.type) {
                case 'login':
                    this.test = true;
                    break;
            }
        }
    });
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 gabriel.hayes
Solution 2 Zoran
Solution 3
Solution 4