Vue 3 wiederverwendbare Fehlerbehandlung und wiederverwendbare handleSubmit-Funktionen in „useForm' mithilfe der Kompositions-API
P粉020556231
P粉020556231 2024-03-27 16:23:57
0
1
467

In einer aktuellen Web-App hatten wir viele Formulare mit der gleichen Einreichungsstruktur:

  1. Deaktivieren Sie Formular- und Senden-Schaltflächen basierend auf isSubmittingVariablen
  2. Eingabefelder validieren (wir verwenden Yup)
  3. Wenn die Validierung fehlschlägt: isSubmitting 设置回 false + 设置并在输入字段上显示 validationErrors wieder auf „false“ setzen + validationErrors festlegen und im Eingabefeld anzeigen
  4. Wenn die Verifizierung erfolgreich ist: Post-Anfrage mit Formulardaten an API senden
  5. Wenn die API geschlossen ist oder einen Fehler zurückgibt, zeigen Sie einen allgemeinen Fehler an

Ich habe versucht, einige Vorgänge mit der Kompositions-API in Vue 3 durchzuführen.

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 };
}

Das funktioniert einigermaßen, aber mir fehlen zwei Dinge. In useForm möchte ich warten, bis der Rückruf abgeschlossen ist (Erfolg oder Misserfolg), bevor ich useForm 中,我想等到回调完成(成功或失败)才能将 isSubmitting 设置回 false。承诺是做到这一点的好方法吗?还有更好的方法吗?其次,我想要一种可重用的方法来处理 Login.vue wieder auf „false“ zurücksetze. Ist Engagement ein guter Weg, dies zu tun? Gibt es einen besseren Weg? Zweitens möchte ich eine wiederverwendbare Möglichkeit zur Behandlung von Fehlern in Login.vue. Irgendwelche Vorschläge, wie mit diesem Problem umgegangen werden kann?

P粉020556231
P粉020556231

Antworte allen(1)
P粉301523298

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

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

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

Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage