简体   繁体   中英

How can I handle a vuex dispatch response?

I'm raising the white flag and asking for suggestions even though I feel the answer is probably right in front of my face.

I have a login form that I am submitting to an api (AWS) and acting on the result. The issue I am having is once the handleSubmit method is called, I am immediately getting into the console.log statement... which to no surprise returns dispatch result: undefined

I realize this is likely not a direct function of vue.js, but how I have the javascript set executing.

Here is my login component:

// SignInForm.vue

handleSubmit() {
    try {
        const {username, password} = this.form;

        this.$store.dispatch('user/authenticate', this.form).then(res => {
            console.log('dispatch result: ', res);
        });
    } catch (error) {
        console.log("Error: SignInForm.handleSubmit", error);
    }
},
...

Here is what my store is doing. I'm sending it to a UserService I've created. Everything is working great. I am getting the correct response(s) and can log everything out I need. The UserService is making an axios request (AWS Amplify) and returning the response.

// user.js (vuex store)

authenticate({state, commit, dispatch}, credentials) {
    dispatch('toggleLoadingStatus', true);

    UserService.authenticate(credentials)
        .then(response => {
            dispatch('toggleLoadingStatus', false);

            if (response.code) {
                dispatch("setAuthErrors", response.message);
                dispatch('toggleAuthenticated', false);
                dispatch('setUser', undefined);

                // send error message back to login component
            } else {
                dispatch('toggleAuthenticated', true);
                dispatch('setUser', response);

                AmplifyEventBus.$emit("authState", "authenticated");

                // Need to move this back to the component somehow
                //     this.$router.push({
                //         name: 'dashboard',
                //     });
            }

            return response;
        });
},
...

Where I'm getting stuck at is, if I have error(s) I can set the errors in the state, but I'm not sure how to access them in the other component. I've tried setting the data property to a computed method that looks at the store, but I get errors.

I'm also struggling to use vue-router if I'm successfully authenticated. From what I've read I really don't want to be doing that in the state anyway -- so that means I need to return the success response back to the SignInForm component so I can use vue-router to redirect the user to the dashboard.

Yep. Just took me ~6 hours, posting to SO and then re-evaluating everything (again) to figure it out. It was in fact, somewhat of a silly mistake. But to help anyone else here's what I was doing wrong...

// SignInForm.vue

async handleSubmit() {
    try {
        await this.$store.dispatch("user/authenticate", this.form)
            .then(response => {
                console.log('SignInForm.handleSubmit response: ', response);  // works

            if (response.code) {
                this.errors.auth.username = this.$store.getters['user/errors'];
            } else {
                this.$router.push({
                    name: 'dashboard',
                });
            }
        }).catch(error => {
            console.log('big problems: ', error);
        });
    } catch (error) {
        console.log("Error: SignInForm.handleSubmit", error);
    }
},
...

Here's my first mistake: I was calling from an async method to another method - but not telling that method to be async so the call(er) method response was executing right away. Here's the updated vuex store:

 // user.js (vuex store)

 async authenticate({state, commit, dispatch}, credentials) { // now async
    dispatch('toggleLoadingStatus', true);

    return await UserService.authenticate(credentials)
        .then(response => {
            console.log('UserService.authenticate response: ', response);  // CognitoUser or code

            dispatch('toggleLoadingStatus', false);

            if (response.code) {
                dispatch("setAuthErrors", response.message);
                dispatch('toggleAuthenticated', false);
                dispatch('setUser', undefined);
            } else {
                dispatch('toggleAuthenticated', true);
                dispatch('setUser', response);

                AmplifyEventBus.$emit("authState", "authenticated");
            }

            return response;
        });
},
...

My second error was that I wasn't returning the result of the method at all from the vuex store.

Old way:

UserService.authenticate(credentials)

Better way:

return await UserService.authenticate(credentials)

Hope this saves someone a few hours. ¯_(ツ)_/¯

This works for Vue3:

export default {
    name: 'Login',
    methods: {
        loginUser: function () {
            authenticationStore.dispatch("loginUser", {
                email: 'peter@example.com',
            })
            .then(response => {
                if (response.status === 200) {
                    console.log('Do something')
                }
            });
        },
    },
}

In the store you can simply pass back the http response which is a promise.

const authenticationStore = createStore({
    actions: {
        loginUser({commit}, {email}) {
            const data = {
                email: email
            };

            return axios.post(`/authentication/login/`, data)
                .then(response => {
                    toastr.success('Success')
                    return response
                })
        },

    }
})

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM