Tip #1 - Ajouter un délai avant validation (debounce)
Lorsqu'on souhaite valider un input à la fin d'une saisie, introduire un léger délai avant vérification évite d'enclencher une validation prématurée inutile. Cette pause pour s'assurer que l'input est "stabilisé" avant de le tester permet d'optimiser notre formulaire surtout si la validation requiert un appel API.
Si on combine OnChangeAsyncDebounceMs avec onChangeAsync on peut ainsi trouver un rythme de validation plus intelligent 👇
function validateUsername(value: string) {
fetch(`/api/validate-username?username=${value}`)
.then(response => response.json())
.then(data => {
if (data.error) {
return "Ce nom d'utilisateur est déjà pris"
}
return null
})
.catch(error => {
return "Une erreur est survenue lors de la validation du nom d'utilisateur"
})
}
<form.Field
name="username"
validators={
// On prend ici pour l'exemple une validation asynchrone
// mais on peut aussi introduire un debounce sur une validation synchrone
onChangeAsyncDebounceMs: 500,
onChangeAsync: ({ value }) => validateUsername(value),
onChange: ({ value }) => {
if (value.length < 3) {
return "Le nom d'utilisateur doit contenir au moins 3 caractères"
Tip #2 - Ajouter un indicateur de validation en cours
Quelle que soit la durée de la validation, n'importe quel champ peut afficher son propre indicateur de validation en regardant son field.getMeta().isValidating.
{field.getMeta().isValidating && <div>Validation en cours...</div>}
</>
}
/>
Tip #3 - Valider plusieurs champs en même temps
Pensons à l'exemple courant d'un formulaire de création de compte comportant un champ pour entrer un mot de passe et un autre pour le confirmer en le rentrant à l'identique. Chacun de ces champs n'est valide que si l'autre contient la même valeur.
En précisant à onChangeListenTo ou onBlurListenTo le tableau de champs qu'on souhaite lui lier, on s'assure que les deux champs sont toujours re-validés en même temps même si l'utilisateur n'interagit qu'avec l'un des deux.
<form.Field
name="password"
validators={{
onChangeListenTo: ["confirmPassword"],
onChange: ({ value, fieldApi }) => {
if (value !== fieldApi.form.getFieldValue("confirmPassword")) {
On remarquera au passage que nous pouvons récupérer au niveau du field n'importe quelle valeur du form grâce à fieldApi.form.getFieldValue() 🤓
Tip #4 - Utiliser une librairie de validation externe
Plutôt que de définir notre logique de validation à l'aide de fonctions passées dans les validators du formulaire ou du champ, TanStack Form laisse la possibilité d'utiliser des schémas de validation de Zod, Valibot, ArkType et autres librairies pour définir nos règles.
L'association de TanStack Form avec une librairie de validation requiert parfois d'installer un adaptateur pour faire le pont entre les deux. Dans le cas de Zod, on l'obtient avec npm install @tanstack/zod-form-adapter
On passe ensuite notre schéma de validation à onChange, onBlurou onSubmit au niveau du champ... 👇
import { zodValidator } from "@tanstack/zod-form-adapter"
import { z } from "zod"
import { useForm } from "@tanstack/react-form"
const PasswordSchema = z.string().min(8, "Le mot de passe doit contenir au moins 8 caractères")
<form.Field
name="password"
validators={{
onChange: ({ value, fieldApi }) => {
if (value !== fieldApi.form.getFieldValue("confirmPassword")) {
return "Les mot de passe ne correspondent pas"
}
}
}}
children={({ field })>
<input
id={field.id}
type="password"
name={field.name}
value={field.state.value}
validatorAdapter={zodValidator}
onChange={PasswordSchema}
/>
}
/>
...ou du formulaire tout entier 👇
import { useForm } from "@tanstack/react-form"
import { zodValidator } from "@tanstack/zod-form-adapter"
import { z } from "zod"
const LoginSchema = z.object({
username: z.string().min(3, "Le nom de l'utilisateur doit contenir au moins 3 caractères"),
password: z.string().min(8, "Le mot de passe doit contenir au moins 8 caractères")