Gestion des erreurs réutilisables Vue 3 et fonctions handleSubmit réutilisables dans "useForm" à l'aide de l'API de composition
P粉020556231
P粉020556231 2024-03-27 16:23:57
0
1
468

Dans une application web récente, nous avions beaucoup de formulaires avec la même structure de soumission :

  1. Désactivez les boutons de formulaire et de soumission en fonction de isSubmitting variables
  2. Valider les champs de saisie (nous utilisons Yup)
  3. Si la validation échoue : remettez isSubmitting 设置回 false + 设置并在输入字段上显示 validationErrors sur false + set et affichez validationErrors dans le champ de saisie
  4. Si la vérification réussit : envoyez la demande de publication avec les données du formulaire à l'API
  5. Si l'API est fermée ou renvoie une erreur, affichez une erreur générale

J'ai essayé de faire quelques opérations en utilisant l'API de composition dans la vue 3.

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

Cela fonctionne dans une certaine mesure, mais il me manque deux choses. Dans useForm, je souhaite attendre la fin du rappel (succès ou échec) avant de redéfinir useForm 中,我想等到回调完成(成功或失败)才能将 isSubmitting 设置回 false。承诺是做到这一点的好方法吗?还有更好的方法吗?其次,我想要一种可重用的方法来处理 Login.vue sur false. L’engagement est-il un bon moyen d’y parvenir ? Existe-t-il une meilleure façon ? Deuxièmement, je veux un moyen réutilisable de gérer les erreurs dans Login.vue. Des suggestions sur la façon de résoudre ce problème ?

P粉020556231
P粉020556231

répondre à tous(1)
P粉301523298

Concernant votre première question - try..catch 语句有第三个名为 finally 的语句,该语句始终在 try le bloc d'instructions est exécuté une fois terminé .

Pour répondre à votre deuxième question : les promesses sont un excellent moyen de gérer la logique asynchrone, y compris les situations dans lesquelles l'API à laquelle vous envoyez la requête renvoie une réponse d'erreur, et vous pouvez ensuite décider comment gérer l'expérience utilisateur dans ce cas.

Je ne suis pas sûr de ce que vous entendez par gérer les erreurs dans Login.vue 中的错误是什么意思,但也许您可以简单地将一个空数组道具传递给名为 formErrorsuseForm 并让您的 useForm.js 发出一个update:modelValueLogin.vue de manière réutilisable, mais peut-être pourriez-vous simplement transmettre un accessoire de tableau vide au

useForm nommé 🎜formErrors code> et demandez à votre 🎜useForm.js d'émettre un événement 🎜update:modelValue pour obtenir une liaison bidirectionnelle. 🎜
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal