Maison >interface Web >js tutoriel >Formulaires dynamiques avec discriminatedUnion et React Hook Form

Formulaires dynamiques avec discriminatedUnion et React Hook Form

Susan Sarandon
Susan Sarandonoriginal
2024-12-24 03:41:141053parcourir

Dynamic forms with discriminatedUnion and React Hook Form

La validation des formulaires est un aspect crucial des applications Web modernes. Avec des bibliothèques telles que React Hook Form (RHF) et Zod, vous pouvez valider efficacement les formulaires dynamiques, y compris ceux dotés de structures complexes telles que les méthodes de paiement. Cet article explique comment utiliser à la fois Zod et RHF pour valider dynamiquement les formulaires à l'aide du puissant discriminatedUnion.

Qu'est-ce qu'un syndicat discriminé ?

Une union discriminée est une technique de typage avancée utilisée pour modéliser des objets avec des structures différentes mais partageant un champ discriminant commun. Ce champ discriminant est utilisé pour identifier le sous-type utilisé et pour effectuer une validation ou une manipulation en conséquence.
Par exemple, considérons un formulaire de paiement qui peut contenir trois types de moyens de paiement :

  1. Carte de crédit (nécessite un numéro de carte et un CVV)
  2. PayPal (nécessite une adresse e-mail)
  3. Virement bancaire (nécessite un numéro de compte et un code bancaire). Chacun de ces types peut être modélisé à l'aide d'une Union discriminée Exemple de modélisation de données avec Zod
import * as zod from "zod"

const IsNotEmptyString = (message: string) => zod.string({message}).min(1, {message})


export enum PaymentMethodEnum {
   CREDIT_CARD ="creditCard", 
   PAYPAL = "paypal", 
   BANKTRANSFER ="bankTransfer"
}

  const creditCardSchema = zod.object({
   type: zod.literal(PaymentMethodEnum.CREDIT_CARD),
   cardNumber: zod.string().regex(/^\d{16}$/, "The card number must contain 16 digits"),
   cvv: zod.string().regex(/^\d{3}$/, "The Card Validation Code must contain 3 digits"),
 })

 const paypalSchema =  zod.object({
   type: zod.literal(PaymentMethodEnum.PAYPAL),
   email: zod.string().email("PayPal email is invalid"),
 })

 const bankTransferSchema =  zod.object({
   type: zod.literal(PaymentMethodEnum.BANKTRANSFER),
   accountNumber: IsNotEmptyString("The account number must contain at least 10 characters"),
   bankCode: IsNotEmptyString("The bank code must contain at least 4 characters")
 })

export const paymentMethodSchema =  () => zod.discriminatedUnion("type",[
   creditCardSchema, paypalSchema,bankTransferSchema
]); 

export type PaymentMethodSchemaType = zod.infer < ReturnType <typeof paymentMethodSchema>>

**

Comment fonctionne la validation ?

**

  1. discriminatedUnion inspecte le champ type :

    • Si le type est 'creditCard', Zod valide selon les contraintes définies dans le premier objet.
    • Si le type est « paypal », il vérifie uniquement les règles liées à l'objet PayPal.
    • Si le type est 'bankTransfer', il valide selon les critères du virement bancaire.
  2. Validation stricte :

    • Chaque type est indépendant. Si un utilisateur fournit un type non valide ou omet un champ obligatoire, Zod déclenche une erreur spécifique.
  3. Simplicité du formulaire React Hook :

    • Le schéma permet à RHF d'adapter dynamiquement la validation selon le champ type, simplifiant la logique dans le formulaire.

**

Pourquoi utiliser ici un syndicat discriminé ?

**

  1. Séparation claire des responsabilités
    • Chaque mode de paiement des règles spécifiques qui ne doivent pas interférer les uns avec les autres interférer.
  2. Flexibilité
    • Autorise de nouveaux types (par exemple un nouveau paiement méthode) pour être ajouté facilement. types (par exemple, un nouveau mode de paiement).
  3. Sécurité
    • Garantit que toutes les valeurs non valides sont détectées à délai de validation.

**

Intégration avec React Hook Form

**
React Hook Form facilite la gestion des formulaires tout en restant performant et flexible. Voici comment intégrer Zod et RHF pour valider un formulaire basé sur discriminatedUnion.

importer { useForm, SubmitHandler, FieldErrors } depuis 'react-hook-form' ;
importer { zodResolver } depuis '@hookform/resolvers/zod' ;
importer './payment.css';
importer {
  PaymentMethodEnum,
  schéma de méthode de paiement,
  Type de schéma de méthode de paiement,
} depuis '../validators/validate-payment-schema';

const Paiement = () => {
  const form = useForm<PaymentMethodSchemaType>({
    résolveur : zodResolver(paymentMethodSchema()),
    valeurs par défaut : {
      tapez : PaymentMethodEnum.CREDIT_CARD,
    },
  });

  const { registre, formState, handleSubmit } = formulaire ;

  const { erreurs } = formState ;

  const paymentType = form.watch().type;

  const handleChangePaymentType = (type : PaymentMethodEnum) => {
    form.setValue('type', type);
  } ;

  const handleResetForm = () => {
    form.reset(GetErrorState(paymentType));
  } ;

  const onSubmit : SubmitHandler<PaymentMethodSchemaType> = (données) => {
    console.log('données', données);
  } ;

  const PaymentTypeFormNode : React.ReactNode = (() => {
    commutateur (type de paiement) {
      cas PaymentMethodEnum.BANKTRANSFER :
        const bankTransferErrors = getErrorsByPaymentType (erreurs, paymentType);

        retour (
          <div>
            <div className="formulaire">
              <étiquette>Numéro de compte</étiquette>
              <entrée
                {...register('accountNumber')}
                placeholder="Entrez votre numéro de compte"
              />
              {bankTransferErrors?.accountNumber?.message && (
                <span className="message d'erreur">
                  {bankTransferErrors.accountNumber.message}
                </envergure>
              )}
            </div>

            <div className="formulaire">
              <étiquette>Code banque</étiquette>
              <entrée
                {...s'inscrire('bankCode')}
                placeholder="Entrez votre code banque"
              />
              {bankTransferErrors?.bankCode?.message && (
                <span className="message d'erreur">
                  {bankTransferErrors.bankCode.message}
                </envergure>
              )}
            </div>
          </div>
        );

      cas PaymentMethodEnum.CREDIT_CARD :
        const creditCardErrors = getErrorsByPaymentType(erreurs, paymentType);
        retour (
          <div>
            <div className="formulaire">
              <étiquette>Numéro de carte</étiquette>
              <entrée
                {...register('cardNumber')}
                placeholder="Entrez votre numéro de carte"
              />
              {creditCardErrors?.cardNumber && (
                <span className="message d'erreur">
                  {creditCardErrors.cardNumber.message}
                </envergure>
              )}
            </div>

            <div className="formulaire">
              <étiquette>CVV</étiquette>
              <entrée
                {...s'inscrire('cvv')}
                placeholder="Entrez le code de validation de votre carte"
              />
              {creditCardErrors?.cvv && (
                <span className="message d'erreur">
                  {creditCardErrors.cvv.message}
                </envergure>
              )}
            </div>
          </div>
        );

      cas PaymentMethodEnum.PAYPAL :
        const paypalErrors = getErrorsByPaymentType (erreurs, paymentType);
        retour (
          <div className="formulaire">
            <label>E-mail</label>
            <entrée
              type="e-mail"
              {...s'inscrire('email')}
              placeholder="Entrez votre email"
            />
            {paypalErrors?.email?.message && (
              <span className="errormessage">{paypalErrors.email.message}</span>
            )}
          </div>
        );

      défaut:
        lancer une nouvelle erreur (
          'Erreur de garde exhaustive : valeur reçue' paymentType
        );
    }
  })();

  retour (
    <form className="form-wrapper" onSubmit={handleSubmit(onSubmit)}>
      <div className="form">



<p>**</p>

<h2>
  
  
  Conclusion
</h2>

<p>**<br>
Alors voilà, les amis. J'espère que vous avez trouvé cet article utile. discriminatedUnion est un type d’utilitaire qui peut être utilisé de plusieurs manières. Si vous pensez qu'il existe d'autres façons d'utiliser discriminatedUnion, veuillez me le faire savoir dans les commentaires. Merci d'avoir lu cet article. On se voit tous dans mon prochain article ?.</p>

<p>Lien de l'application test : <br>
https://stackblitz.com/edit/vitejs-vite-ppgw9zrb?file=src/pages/payments.tsx</p>


          

            
        

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn