Mutation des données
Dans le chapitre précédent, vous avez implémenté la recherche et la pagination en utilisant les paramètres de recherche d'URL et les API de Next.js. Continuons à travailler sur la page des factures en ajoutant la capacité de créer, mettre à jour et supprimer des factures !
Que sont les Actions Serveur ?
Les Actions Serveur de React vous permettent d'exécuter du code asynchrone directement sur le serveur. Elles éliminent le besoin de créer des points de terminaison d'API pour mutuer vos données. Au lieu de cela, vous écrivez des fonctions asynchrones qui s'exécutent sur le serveur et peuvent être invoquées depuis vos composants Client ou Serveur.
La sécurité est une priorité absolue pour les applications web, car elles peuvent être vulnérables à diverses menaces. C'est là qu'interviennent les Actions Serveur. Elles incluent des fonctionnalités comme les fermetures cryptées, les vérifications strictes des entrées, le hachage des messages d'erreur, les restrictions d'hôte, et plus encore — toutes travaillant ensemble pour améliorer significativement la sécurité de votre application.
Utilisation des formulaires avec les Actions Serveur
Dans React, vous pouvez utiliser l'attribut action
dans l'élément <form>
pour invoquer des actions. L'action recevra automatiquement l'objet natif FormData, contenant les données capturées.
Par exemple :
Un avantage d'invoquer une Action Serveur dans un composant Serveur est l'amélioration progressive — les formulaires fonctionnent même si JavaScript n'a pas encore été chargé sur le client. Par exemple, avec des connexions internet plus lentes.
Next.js avec les Actions Serveur
Les Actions Serveur sont également profondément intégrées avec le cache de Next.js. Lorsqu'un formulaire est soumis via une Action Serveur, vous pouvez non seulement utiliser l'action pour mutuer les données, mais aussi revalider le cache associé en utilisant des API comme revalidatePath
et revalidateTag
.
Voyons comment tout cela fonctionne ensemble !
Création d'une facture
Voici les étapes que vous suivrez pour créer une nouvelle facture :
- Créez un formulaire pour capturer les entrées de l'utilisateur.
- Créez une Action Serveur et invoquez-la depuis le formulaire.
- Dans votre Action Serveur, extrayez les données de l'objet
formData
. - Validez et préparez les données à être insérées dans votre base de données.
- Insérez les données et gérez les erreurs éventuelles.
- Revalidez le cache et redirigez l'utilisateur vers la page des factures.
1. Créez une nouvelle route et un formulaire
Pour commencer, dans le dossier /invoices
, ajoutez un nouveau segment de route appelé /create
avec un fichier page.tsx
:

Vous utiliserez cette route pour créer de nouvelles factures. Dans votre fichier page.tsx
, collez le code suivant, puis prenez le temps de l'étudier :
Votre page est un composant Serveur qui récupère les customers
et les passe au composant <Form>
. Pour gagner du temps, nous avons déjà créé le composant <Form>
pour vous.
Naviguez vers le composant <Form>
, et vous verrez que le formulaire :
- A un élément
<select>
(menu déroulant) avec une liste de clients. - A un élément
<input>
pour le montant avectype="number"
. - A deux éléments
<input>
pour le statut avectype="radio"
. - A un bouton avec
type="submit"
.
Sur http://localhost:3000/dashboard/invoices/create, vous devriez voir l'interface utilisateur suivante :

2. Créez une Action Serveur
Super, maintenant créons une Action Serveur qui sera appelée lorsque le formulaire est soumis.
Naviguez vers votre répertoire lib/
et créez un nouveau fichier nommé actions.ts
. Au début de ce fichier, ajoutez la directive React use server
:
En ajoutant 'use server'
, vous marquez toutes les fonctions exportées dans le fichier comme des Actions Serveur. Ces fonctions serveur peuvent ensuite être importées et utilisées dans les composants Client et Serveur. Toutes les fonctions incluses dans ce fichier qui ne sont pas utilisées seront automatiquement supprimées du bundle final de l'application.
Vous pouvez également écrire des Actions Serveur directement dans les composants Serveur en ajoutant "use server"
à l'intérieur de l'action. Mais pour ce cours, nous les garderons toutes organisées dans un fichier séparé. Nous recommandons d'avoir un fichier séparé pour vos actions.
Dans votre fichier actions.ts
, créez une nouvelle fonction asynchrone qui accepte formData
:
Ensuite, dans votre composant <Form>
, importez createInvoice
depuis votre fichier actions.ts
. Ajoutez un attribut action
à l'élément <form>
, et appelez l'action createInvoice
.
Bon à savoir : En HTML, vous passeriez une URL à l'attribut
action
. Cette URL serait la destination où les données de votre formulaire devraient être soumises (généralement un point de terminaison d'API).Cependant, dans React, l'attribut
action
est considéré comme une prop spéciale — ce qui signifie que React s'appuie dessus pour permettre aux actions d'être invoquées.En arrière-plan, les Actions Serveur créent un point de terminaison d'API
POST
. C'est pourquoi vous n'avez pas besoin de créer manuellement des points de terminaison d'API lorsque vous utilisez des Actions Serveur.
3. Extrayez les données de formData
Retour dans votre fichier actions.ts
, vous devrez extraire les valeurs de formData
, il existe quelques méthodes que vous pouvez utiliser. Pour cet exemple, utilisons la méthode .get(name)
.
Astuce : Si vous travaillez avec des formulaires ayant de nombreux champs, vous pouvez envisager d'utiliser la méthode
entries()
avecObject.fromEntries()
de JavaScript.
Pour vérifier que tout est connecté correctement, testez le formulaire. Après soumission, vous devriez voir les données que vous venez d'entrer dans le formulaire enregistrées dans votre terminal (pas dans le navigateur).
Maintenant que vos données sont sous forme d'objet, il sera beaucoup plus facile de travailler avec.
4. Validez et préparez les données
Avant d'envoyer les données du formulaire à votre base de données, vous voulez vous assurer qu'elles sont dans le bon format et avec les bons types. Si vous vous souvenez du début du cours, votre table des factures attend des données dans le format suivant :
Jusqu'à présent, vous n'avez que le customer_id
, le amount
et le status
du formulaire.
Validation et coercition de type
Il est important de valider que les données de votre formulaire correspondent aux types attendus dans votre base de données. Par exemple, si vous ajoutez un console.log
dans votre action :
Vous remarquerez que amount
est de type string
et non number
. C'est parce que les éléments input
avec type="number"
retournent en réalité une chaîne, pas un nombre !
Pour gérer la validation des types, vous avez quelques options. Bien que vous puissiez valider manuellement les types, utiliser une bibliothèque de validation peut vous faire gagner du temps et des efforts. Pour votre exemple, nous utiliserons Zod, une bibliothèque de validation TypeScript-first qui peut simplifier cette tâche pour vous.
Dans votre fichier actions.ts
, importez Zod et définissez un schéma qui correspond à la forme de votre objet formulaire. Ce schéma validera le formData
avant de le sauvegarder dans une base de données.
Le champ amount
est spécifiquement configuré pour forcer (changer) d'une chaîne à un nombre tout en validant son type.
Vous pouvez ensuite passer votre rawFormData
à CreateInvoice
pour valider les types :
Stockage des valeurs en centimes
C'est généralement une bonne pratique de stocker les valeurs monétaires en centimes dans votre base de données pour éliminer les erreurs de virgule flottante de JavaScript et garantir une plus grande précision.
Convertissons le montant en centimes :
Création de nouvelles dates
Enfin, créons une nouvelle date avec le format "AAAA-MM-JJ" pour la date de création de la facture :
5. Insertion des données dans votre base de données
Maintenant que vous avez toutes les valeurs nécessaires pour votre base de données, vous pouvez créer une requête SQL pour insérer la nouvelle facture dans votre base de données et passer les variables :
Pour l'instant, nous ne gérons aucune erreur. Nous en parlerons dans le prochain chapitre. Pour l'instant, passons à l'étape suivante.
6. Révalidation et redirection
Next.js dispose d'un cache de routeur côté client qui stocke les segments de route dans le navigateur de l'utilisateur pendant un certain temps. Combiné avec le préchargement (prefetching), ce cache garantit que les utilisateurs peuvent naviguer rapidement entre les routes tout en réduisant le nombre de requêtes envoyées au serveur.
Comme vous mettez à jour les données affichées dans la route des factures, vous souhaitez effacer ce cache et déclencher une nouvelle requête vers le serveur. Vous pouvez le faire avec la fonction revalidatePath
de Next.js :
Une fois la base de données mise à jour, le chemin /dashboard/invoices
sera révalidé et les données fraîches seront récupérées depuis le serveur.
À ce stade, vous souhaitez également rediriger l'utilisateur vers la page /dashboard/invoices
. Vous pouvez le faire avec la fonction redirect
de Next.js :
Félicitations ! Vous venez d'implémenter votre première Action Serveur (Server Action). Testez-la en ajoutant une nouvelle facture. Si tout fonctionne correctement :
- Vous devriez être redirigé vers la route
/dashboard/invoices
après la soumission. - Vous devriez voir la nouvelle facture en haut du tableau.
Mettre à jour une facture
Le formulaire de mise à jour d'une facture est similaire au formulaire de création, sauf que vous devrez passer l'id
de la facture pour mettre à jour l'enregistrement dans votre base de données. Voyons comment vous pouvez obtenir et passer l'id
de la facture.
Voici les étapes que vous suivrez pour mettre à jour une facture :
- Créer un nouveau segment de route dynamique avec l'
id
de la facture. - Lire l'
id
de la facture à partir des paramètres de la page. - Récupérer la facture spécifique depuis votre base de données.
- Pré-remplir le formulaire avec les données de la facture.
- Mettre à jour les données de la facture dans votre base de données.
1. Créer un segment de route dynamique avec l'id
de la facture
Next.js vous permet de créer des Segments de Route Dynamiques (Dynamic Route Segments) lorsque vous ne connaissez pas le nom exact du segment et que vous souhaitez créer des routes basées sur des données. Cela peut être des titres d'articles de blog, des pages de produits, etc. Vous pouvez créer des segments de route dynamiques en entourant le nom d'un dossier de crochets. Par exemple, [id]
, [post]
ou [slug]
.
Dans votre dossier /invoices
, créez une nouvelle route dynamique appelée [id]
, puis une nouvelle route appelée edit
avec un fichier page.tsx
. La structure de vos fichiers devrait ressembler à ceci :
![Dossier Invoices avec un dossier imbriqué [id], et un dossier edit à l'intérieur](https://h8DxKfmAPhn8O0p3.public.blob.vercel-storage.com/learn/light/edit-invoice-route.png)
Dans votre composant <Table>
, remarquez qu'il y a un bouton <UpdateInvoice />
qui reçoit l'id
de la facture à partir des enregistrements du tableau.
Accédez à votre composant <UpdateInvoice />
et mettez à jour le href
du Link
pour accepter la prop id
. Vous pouvez utiliser des littéraux de gabarit pour créer un lien vers un segment de route dynamique :
2. Lire l'id
de la facture à partir des params
de la page
Dans votre composant <Page>
, collez le code suivant :
Remarquez que c'est similaire à votre page de création de facture, sauf qu'elle importe un formulaire différent (depuis le fichier edit-form.tsx
). Ce formulaire doit être pré-rempli avec une defaultValue
pour le nom du client, le montant de la facture et le statut. Pour pré-remplir les champs du formulaire, vous devez récupérer la facture spécifique en utilisant l'id
.
En plus de searchParams
, les composants de page acceptent également une prop appelée params
que vous pouvez utiliser pour accéder à l'id
. Mettez à jour votre composant <Page>
pour recevoir cette prop :
3. Récupérer la facture spécifique
Ensuite :
- Importez une nouvelle fonction appelée
fetchInvoiceById
et passez-lui l'id
comme argument. - Importez
fetchCustomers
pour récupérer les noms des clients pour le menu déroulant.
Vous pouvez utiliser Promise.all
pour récupérer à la fois la facture et les clients en parallèle :
Vous verrez une erreur TypeScript temporaire pour la prop invoice
dans votre terminal car invoice
pourrait potentiellement être undefined
. Ne vous inquiétez pas pour l'instant, vous la résoudrez dans le prochain chapitre lorsque vous ajouterez la gestion des erreurs.
Super ! Maintenant, testez que tout est correctement connecté. Visitez http://localhost:3000/dashboard/invoices et cliquez sur l'icône Crayon pour modifier une facture. Après la navigation, vous devriez voir un formulaire pré-rempli avec les détails de la facture :

L'URL devrait également être mise à jour avec un id
comme suit : http://localhost:3000/dashboard/invoice/uuid/edit
UUIDs vs. Clés auto-incrémentées
Nous utilisons des UUIDs au lieu de clés auto-incrémentées (par exemple, 1, 2, 3, etc.). Cela rend l'URL plus longue ; cependant, les UUIDs éliminent le risque de collision d'ID, sont globalement uniques et réduisent le risque d'attaques par énumération - ce qui les rend idéaux pour les grandes bases de données.
Cependant, si vous préférez des URLs plus propres, vous pourriez préférer utiliser des clés auto-incrémentées.
4. Passer l'id
à l'Action Serveur
Enfin, vous souhaitez passer l'id
à l'Action Serveur afin de pouvoir mettre à jour le bon enregistrement dans votre base de données. Vous ne pouvez pas passer l'id
comme argument comme ceci :
À la place, vous pouvez passer l'id
à l'Action Serveur en utilisant JS bind
. Cela garantira que toutes les valeurs passées à l'Action Serveur sont encodées.
Remarque : Utiliser un champ input caché dans votre formulaire fonctionne également (par exemple
<input type="hidden" name="id" value={invoice.id} />
). Cependant, les valeurs apparaîtront en texte clair dans le code source HTML, ce qui n'est pas idéal pour les données sensibles.
Ensuite, dans votre fichier actions.ts
, créez une nouvelle action, updateInvoice
:
De manière similaire à l'action createInvoice
, ici vous :
- Extrayez les données de
formData
. - Validez les types avec Zod.
- Convertissez le montant en centimes.
- Passez les variables à votre requête SQL.
- Appelez
revalidatePath
pour effacer le cache client et faire une nouvelle requête serveur. - Appelez
redirect
pour rediriger l'utilisateur vers la page des factures.
Testez-la en modifiant une facture. Après avoir soumis le formulaire, vous devriez être redirigé vers la page des factures et la facture devrait être mise à jour.
Supprimer une facture
Pour supprimer une facture en utilisant une Action Serveur, enveloppez le bouton de suppression dans un élément <form>
et passez l'id
à l'Action Serveur en utilisant bind
:
Dans votre fichier actions.ts
, créez une nouvelle action appelée deleteInvoice
.
Comme cette action est appelée dans le chemin /dashboard/invoices
, vous n'avez pas besoin d'appeler redirect
. Appeler revalidatePath
déclenchera une nouvelle requête serveur et re-rendra le tableau.
Pour aller plus loin
Dans ce chapitre, vous avez appris à utiliser les Actions Serveur pour muter des données. Vous avez également appris à utiliser l'API revalidatePath
pour révalider le cache Next.js et redirect
pour rediriger l'utilisateur vers une nouvelle page.
Vous pouvez également en apprendre davantage sur la sécurité avec les Actions Serveur (Server Actions) pour approfondir vos connaissances.