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:

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.

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 ?

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 !