Vue 3 可重用错误处理和 handleSubmit 在可重用“useForm”函数中使用组合 api

Posted

技术标签:

【中文标题】Vue 3 可重用错误处理和 handleSubmit 在可重用“useForm”函数中使用组合 api【英文标题】:Vue 3 reusable error handling and handleSubmit in reusable 'useForm' function using the composition api 【发布时间】:2022-01-22 18:31:59 【问题描述】:

在最近的一个网络应用中,我们有很多具有相同提交结构的表单:

    根据isSubmitting 变量禁用表单和提交按钮 验证输入字段(我们使用Yup) 如果验证失败:将 isSubmitting 设置回 false + 设置并在输入字段中显示 validationErrors 如果验证成功:将带有表单数据的 post 请求发送到 api 如果 api 关闭或返回错误,则显示一般错误

我尝试过在 vue 3 中使用组合 API。

Login.vue

<template>
    <div class="min-h-full flex flex-col justify-center py-12 sm:px-6 lg:px-8">
        <div class="sm:mx-auto sm:w-full sm:max-w-md">
            <h1 class="text-3xl text-center text-gray-900"> t('sign_in_account', 1) </h1>
        </div>

        <div class="mt-8 sm:mx-auto sm:w-full sm:max-w-md">
            <div class="bg-white py-8 px-4 shadow sm:rounded-lg sm:px-10">
                <form @submit.prevent="handleSubmit">
                    <fieldset :disabled="isSubmitting" class="space-y-6">
                        <MessageBox v-if="errors.general" :title="errors.general" :messages="errors.messages" />
                        <Input :label="t('email', 1)" type="text" id="email" v-model="user.email" :error="errors.email" />
                        <Password :label="t('password', 1)" type="password" id="password" v-model="user.password" :error="errors.password" />

                        <div class="text-sm text-right">
                            <router-link class="font-medium text-indigo-600 hover:text-indigo-500" :to="forgotPassword"> t('forgot_password', 1) </router-link>
                        </div>

                        <SubmitButton class="w-full" :label="t('sign_in', 1)" :submittingLabel="t('sign_in_loader', 1)" :isSubmitting="isSubmitting" />
                    </fieldset>
                </form>
            </div>
        </div>
    </div>
</template>

<script>
    import  ref  from 'vue';
    import  useStore  from 'vuex';
    import  useI18n  from 'vue-i18n';

    import useForm from '@/use/useForm';
    import  validateEmail, LoginValidationSchema  from '@/utils/validators';

    export default 
        setup() 
            const store = useStore();
            const  t  = useI18n( useScope: 'global' );

            const user = ref(
                email: '',
                password: '',
            );

            const  handleSubmit, isSubmitting, errors  = useForm(user, LoginValidationSchema, handleLogin);

            async function handleLogin(values) 
                try 
                    return await store.dispatch('auth/login', values);
                 catch (error) 
                    if (error.response) 
                        console.log(error.reponse);
                        if (error.response.status == 422) 
                            errors.value = 
                                general: `$t('unable_to_login', 1)<br /> $t('fix_and_retry', 1)`,
                                messages: Object.values(error.response.data.errors).flat(),
                            ;
                         else if (error.response.data.message) 
                            errors.value = 
                                general: error.response.data.message,
                            ;
                         else 
                            errors.value = 
                                general: `$t('unknown_error', 1)<br /> $t('please_try_agin', 1)`,
                            ;
                        
                     else if (error.request) 
                        console.log(error.request);
                        errors.value = 
                            general: `$t('unknown_error', 1)<br /> $t('please_try_agin', 1)`,
                        ;
                     else 
                        errors.value = 
                            general: `$t('unknown_error', 1)<br /> $t('please_try_agin', 1)`,
                        ;
                    

                    return;
                
            

            return  t, user, handleSubmit, isSubmitting, errors ;
        ,
        computed: 
            forgotPassword() 
                return validateEmail(this.user.email) ?  name: 'forgotPassword', query:  email: this.user.email   :  name: 'forgotPassword' ;
            ,
        ,
    ;
</script>

useForm.js

import  ref, watch  from 'vue';

export default function useForm(initialValues, validationSchema, callback) 
    let values = ref(initialValues);
    let isSubmitting = ref(false);
    let errors = ref();

    async function handleSubmit() 
        try 
            errors.value = ;
            await validationSchema.validate(values.value,  abortEarly: false );
            isSubmitting.value = true;
         catch (err) 
            console.log('In the catch');
            isSubmitting.value = false;

            err.inner.forEach((error) => 
                errors.value =  ...errors.value, [error.path]: error.message ;
            );
        
    

    watch(isSubmitting, () => 
        if (Object.keys(errors.value).length === 0 && isSubmitting.value) 
            callback(values);
            isSubmitting.value = false;
         else 
            isSubmitting.value = false;
        
    );

    return  handleSubmit, isSubmitting, errors ;

这在某种程度上可行,但我缺少两件事。在useForm 中,我想等到回调完成(成功或失败)将isSubmitting 设置回false。承诺是做到这一点的好方法吗?还有更好的方法吗?其次,我想要一种可重用的方法来处理Login.vue 中的错误。有什么建议如何处理吗?

【问题讨论】:

【参考方案1】:

关于您的第一个问题 - try..catch 语句有第三个语句称为 finally,它始终执行 after try 语句块已完成。

https://developer.mozilla.org/en-US/docs/Web/javascript/Reference/Statements/try...catch

回答您的第二个问题 - 承诺是处理异步逻辑的好方法,包括您发送请求的 API 返回错误响应时的情况,然后您可以决定如何处理这种情况下的用户体验。

我不太清楚您以可重用的方式处理Login.vue 中的错误是什么意思,但也许您可以简单地将一个空数组道具传递给您的useForm,称为formErrors 并让您的@ 987654329@ 发出一个update:modelValue 事件来获得双向绑定。

【讨论】:

以上是关于Vue 3 可重用错误处理和 handleSubmit 在可重用“useForm”函数中使用组合 api的主要内容,如果未能解决你的问题,请参考以下文章

使用 Vue.js 创建可重用的按钮组件

如何在 Vue.js 中访问可重用组件的其他实例的状态

在Vue中创建可重用的 Transition

结合Vue路由器使用Vue 2中的可重用组件

如何在 laravel nova 中创建可重用的 vue 组件?

无法使用 Vue.js 在可重用组件之间添加自定义内容