Vous est-il déjà arrivé de galérer à ajouter des tests sur vos formulaires avec React-Hook-Form ? Pour peu que vous ayez un test custom à mettre en place, que ce soit avec Yup et la fonction .test ou avec Zod et son .refine. Dans cet article nous allons enfin régler ce problème de formState.
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.
Voici à quoi ressemble mon formulaire:
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:
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>
)}
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.
Même si cela ne fonctionne pas encore, à ce stade vous n'êtes plus très loin !
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 ?
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 !
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.
Nous utilisons des cookies sur ce site pour améliorer votre expérience d'utilisateur.