Vuex 动作改变组件数据

Vuex action changes component data

我有以下组件,它只是一个简单的登录表单:

<template>
    <v-card>
        <v-card-title primary-title class="headline white--text primary">Login</v-card-title>
        <form @keyup.enter="submit( form )" @submit.prevent="submit( form )">
            <v-card-text>
                <v-text-field
                    label="Email address"
                    required
                    :error-messages="errors['email']"
                    v-model="form.email"
                />

                <v-text-field
                    label="Password"
                    hint="At least 8 characters"
                    minlength="8"
                    :append-icon="passwordVisible ? 'visibility_off' : 'visibility'"
                    :append-icon-cb="() => (passwordVisible = !passwordVisible)"
                    :type="passwordVisible ? 'text' : 'password'"
                    required
                    counter
                    :error-messages="errors['password']"
                    v-model="form.password"
                />
            </v-card-text>

            <v-card-actions>
                <v-btn type="submit" color="primary">Login</v-btn>
            </v-card-actions>
        </form>
    </v-card>
</template>

<script>
    export default
    {
        metaInfo: {
            title: 'Login'
        },

        data()
        {
            return {
                form: {
                    email: '',
                    password: '',
                },
                passwordVisible: false,
            }
        },

        computed: {    
            errors()
            {
                return this.$store.getters.errors;
            }
        },

        methods: {
            submit( data )
            {
                this.$store.dispatch( 'userLogin', data );
            }
        },
    }
</script>

userLogin 操作看起来像:

userLogin( context, data )
        {
            // Base64 encode password
            data.password = btoa( data.password );

            fetch( '/api/users/login', {
                headers: {
                    'X-Requested-With': 'XMLHttpRequest',
                    'X-CSRF-token': window.token,
                    'Content-Type': 'application/json',
                    'Accept': 'application/json'
                },
                method: 'POST',
                body: JSON.stringify( data )
            })
                .then( response => {
                    return response.json();
                })
                .then( response => {
                    // If there are any errors
                    if( response.errors )
                    {
                        context.commit( 'errors', response.errors );
                    }

                    context.commit( 'message', response.message );
                    context.commit( 'success', response.success ? response.success : false );

                    if( response.token )
                    {
                        context.commit( 'userLogin', response.token );
                    }
                })
                .catch( error => {
                    console.error( 'userLogin', error );
                });
        }

在我尝试登录之前,表单中的所有内容都按预期工作。提交表单后,操作会运行 2 次。第一次我得到了预期的结果,它是由 API 生成的标记。然而,第二次模板中的密码字段已更改为 base64 值。

所以我的问题是为什么这个动作执行了两次?为什么密码字段的值在组件内只有 "stored and read" 时会发生变化?

希望有人能帮我解决问题。

为什么动作执行了两次

您在表单上附加了两个事件侦听器:

  1. @submit.prevent
  2. @keyup.enter

这两个事件的事件处理程序是 submit( form ),它正在调度操作

当您专注于输入字段并点击回车按钮时,表单将被提交 implicitly。 因此 submit( form ) 将被调用两次 ;

  1. 正在调用表单的提交方法
  2. 由于按下回车按钮,@keyup.enter 的事件处理程序也被调用

为什么密码字段的值在组件内只有 "stored and read" 时会发生变化?

您正在将 form 作为负载传递给作为对象的操作:

form: { email: '', password: '', }

在 JavaScript 个对象是 passed by reference. 在您的操作中,您将 form 对象的密码 属性 突变为

data.password = btoa( data.password );

因此更改也反映在组件中

---------------------------------

解决方案

why is the action executed twice

由于输入框处于焦点时按回车键的默认行为是提交表单,因此您可以删除 @keyup.enter 侦听器

Why does the password field value change when the value is only "stored and read" from within the component?

不改变原始对象。而是创建一个新的并将其作为您的 post 请求主体

传递
// Base64 encode password
let details = {
        email: data.email, 
        password: btoa( data.password )
    }

fetch( '/api/users/login', {
    headers: {
        'X-Requested-With': 'XMLHttpRequest',
        'X-CSRF-token': window.token,
        'Content-Type': 'application/json',
        'Accept': 'application/json'
    },
    method: 'POST',
    body: JSON.stringify( details )
})