useButtonFeedback
Exécute une action asynchrone avec chargement, succès et erreur, en évitant le spinner pour les requêtes rapides et en maintenant une erreur le temps de la lire.
pnpm dlx shadcn@latest add https://hextaui.com/r/use-button-feedback.jsonAjoute le hook et tout ce dont il dépend à votre projet.
Copiez et collez le code suivant dans votre projet.
hooks/use-button-feedback.ts Mettez à jour les chemins d’import selon la configuration de votre projet.
<Button feedback> exécute ce flux pour vous quand son onClick renvoie une promesse. Utilisez le hook quand le travail démarre ailleurs, comme le onSubmit d'un formulaire, un raccourci clavier ou un blur. Il fonctionne aussi quand le statut doit s'afficher sur autre chose qu'un bouton.
track() accepte une promesse, ou une fonction qui en renvoie une, et fait passer status par idle, loading, puis success ou error, avant de revenir à idle. C'est le timing qui donne cette impression de calme.
| Étape | Description |
|---|---|
0–150ms | Le statut reste idle. Une requête qui se termine dans cette fenêtre passe directement à success ou error, sans spinner. |
loading | Affiché à partir de 150ms. Une fois affiché, il dure au moins 400ms, pour ne jamais clignoter. |
success | Maintenu 2 secondes par défaut, puis retour à idle. |
error | Maintenu 4 secondes par défaut. Tant que le pointeur est sur le bouton ou qu'il a le focus clavier, la réinitialisation attend leur départ, plus 600ms. |
- Les appels à
track()pendant qu'une requête est en cours sont ignorés : un double-clic ou une touche Enter maintenue n'envoie jamais la requête deux fois. - Une fonction passée à
track()qui lève une exception de façon synchrone est traitée comme une promesse rejetée. reset()revient à idle aussitôt. Tout ce que la requête abandonnée fait plus tard est ignoré, de même que tout ce qui se termine après le démontage du composant.- Le maintien de l'erreur ne compte que le vrai survol à la souris et le focus clavier. Le toucher n'a pas de survol, et le focus d'un clic n'est pas
:focus-visible: ni l'un ni l'autre ne fige donc l'erreur.
Formulaires
Appelez track() depuis onSubmit et répartissez buttonProps sur le bouton d'envoi. Retirez le @ pour voir l'erreur.
Statut sans bouton
Lisez status pour piloter n'importe quelle interface. Cette note s'enregistre quand elle perd le focus et affiche le résultat à côté, dans une région role="status" que les lecteurs d'écran annoncent.
resetAfter accepte un nombre pour les deux issues, ou un objet pour régler chacune. error contient la dernière raison de rejet, que vous pouvez afficher dans le label, comme le fait l'exemple des détails d'erreur de Button.
- Donnez à chaque bouton son propre hook. Deux boutons partageant un même
buttonPropsaffichent tous deux le même statut. onStatusChangeetonErrorappellent toujours la dernière fonction que vous avez passée : les fonctions en ligne conviennent donc.- Utilisez
isPending()pour protéger le travail en dehors detrack(). Il lit une ref, donc il est exact même avant le rendu suivant.
| Prop | Type | Par défaut |
|---|---|---|
resetAfterCombien de temps success et error restent avant le retour à idle. | number | { success?: number; error?: number } | { success: 2000, error: 4000 } |
onStatusChangeAppelé à chaque changement de statut. | (status: ButtonStatus) => void | – |
onErrorAppelé avec la raison du rejet. | (error: unknown) => void | – |
| Propriété | Description |
|---|---|
track(action) | Passez une promesse ou une fonction qui en renvoie une. Ignoré pendant qu'une requête est en cours. |
buttonProps | status ainsi que les gestionnaires de pointeur et de focus. À répartir sur <Button>, ou sur tout élément qui compose ces gestionnaires. |
status | "idle" | "loading" | "success" | "error" |
error | La dernière raison de rejet. |
reset() | Revient à idle immédiatement et ignore la requête en cours. |
isPending() | Indique si une requête est en cours. |
Button via sa prop feedback.