Comment ajouter des validateurs custom sur react-hook-form

Comment ajouter des validateurs custom sur react-hook-form
Alexandre P. dans Dev - mis à jour le 14-12-2024

Maîtrisez les tests de formulaires avec React-Hook-Form, Yup.test ou Zod.refine et résolvez les problèmes de formState facilement.

Le formState de react-hook-form ne se met jamais à jour

const {
    register,
    handleSubmit,
    formState
  } = useForm<PostForm>({
    resolver: zodResolver(postValidationSchema)
  })

Vous est-il déjà arrivé d'avoir errors toujours vide avec votre resolver ?

Lorsque vous loggez formState dans un useEffect.

Commençons par vérifier notre resolver zod

Voici à quoi ressemble mon formulaire:

zod_form.png

Voici le schéma zod:

import { ZodType, z } from "zod"

const isUrl =
  /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/

export const postValidationSchema: ZodType<PostForm> = z
  .object({
    videoUrl: z
      .string()
      .refine((videoUrl) => {
        if (
          videoUrl.length > 0 &&
          isUrl.test(videoUrl) &&
          (!/youtube(.com|.fr|.co.jp|.co.uk|.be)/.test(videoUrl) ||
            !/watch\?v=[a-zA-Z0-9_]{3,}/.test(videoUrl))
        )
          return false
        return true
      }, "must_be_valid_youtube")
      .optional(),
    message: z
      .string()
      .refine((message) => {
        if (message.length > 0 && isUrl.test(message)) return false
        return true
      }, "no_url_in_message")
      .optional()
  })
  .partial()

Avec ce schéma de validation, nous voulons mettre en place les règles suivantes:

  • Un utilisateur doit au moins saisir une videoUrl ou un message
  • La videoUrl est forcément une vidéo provenant de Youtube
  • Le message ne doit contenir aucune url

Puis, nous ajoutons la vérification sur notre bouton de formulaire:

<button
    type="submit"
    disabled={!formState.isValid}
  >
  <IoIosSend className="mr-2 text-2xl" />
  Send the message
</button>

Maintenant, même si ces règles sont appliqués, les messages d'erreur n'arrivent jamais au formulaire:

// que ce soit
{formState.errors?.message && (
  <span className="text-red-700">
    {translate(
      `formState.errors.message.message`,
      lang
    )}
  </span>
)}

// ou encore
{formState.errors?.videoUrl && (
  <span className="text-red-700">
    {translate(
      `formState.errors.videoUrl.message`,
      lang
    )}
  </span>
)}

Où sont passés mes messages d'erreurs ?

Lorsque l'on essait d'afficher les erreurs sur notre formulaire, React-Hook-Form se comporte très bizarrement. Mais rassurez vous, cela n'a rien à voir avec votre schéma zod ou yup.

zod_form_ko.gif

Même si cela ne fonctionne pas encore, à ce stade vous n'êtes plus très loin !

Afficher les messages d'erreur React-Hook-Form correctement

Reprenons notre définition du formulaire:

import { PostForm, postValidationSchema } from "@/customTypes/post"
import { zodResolver } from "@hookform/resolvers/zod"
import { SubmitHandler, useForm } from "react-hook-form"

const {
    register,
    handleSubmit,
    formState,
    watch,
    trigger
  } = useForm<PostForm>({
    resolver: zodResolver(postValidationSchema)
  })

Cette fois-ci, nous allons ajouter watch et trigger.

Watch permettra de déclencher un changement de state à chaque modification de la valeur des champs. Nous pourrons l'utiliser dans un useEffect.

Trigger quant à lui, sert à forcer un passage au resolver, c'est un vrai douanier !

Utilisons-les comme ceci:

React.useEffect(() => {
    const subscription = watch(() => {
      trigger(["message", "videoUrl"])
    })
    return () => subscription.unsubscribe()
  }, [watch, trigger])

Et maintenant, à quoi ressemble notre formulaire ?

zod_form_ok.gif

J'ai l'impression que tout est ok 😊.

J'espère que cet article vous aidera car je me suis arraché les cheveux pendant 2 jours pour résoudre cette incohérence. Bon code !

#react#react-hook-form#zod#resolver

user picture

Alexandre P.

Développeur passionné depuis plus de 20 ans, j'ai une appétence particulière pour les défis techniques et changer de technologie ne me fait pas froid aux yeux.


Votre vie privée

Nous utilisons des cookies pour améliorer votre expérience sur notre site, analyser notre trafic et personnaliser les publicités. En cliquant sur "Accepter", vous consentez à l'utilisation de tous les cookies. Vous pouvez également choisir de refuser en cliquant sur le bouton "Refuser".