Vue 3 可重用错误处理和可重用'useForm”中的handleSubmit使用组合 API 的函数
P粉020556231
P粉020556231 2024-03-27 16:23:57
0
1
416

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

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

我尝试过使用 vue 3 中的组合 api 进行一些操作。

登录.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 中的错误。有什么建议如何处理这个问题吗?

P粉020556231
P粉020556231

全部回复(1)
P粉301523298

关于你的第一个问题 - try..catch 语句有第三个名为 finally 的语句,该语句始终在 try 语句块完成后执行

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

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

热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板