Formulaires et mutations
Les formulaires vous permettent de créer et de mettre à jour des données dans les applications web. Next.js offre une manière puissante de gérer les soumissions de formulaires et les mutations de données en utilisant les routes API.
Bon à savoir :
- Nous recommanderons bientôt d'adopter progressivement le routeur App et d'utiliser les actions serveur (Server Actions) pour gérer les soumissions de formulaires et les mutations de données. Les actions serveur vous permettent de définir des fonctions serveur asynchrones qui peuvent être appelées directement depuis vos composants, sans avoir besoin de créer manuellement une route API.
- Les routes API ne spécifient pas d'en-têtes CORS, ce qui signifie qu'elles sont uniquement de même origine par défaut.
- Comme les routes API s'exécutent sur le serveur, nous pouvons utiliser des valeurs sensibles (comme des clés API) via les variables d'environnement sans les exposer au client. Ceci est crucial pour la sécurité de votre application.
Exemples
Formulaire côté serveur uniquement
Avec le routeur Pages, vous devez créer manuellement des points de terminaison API pour gérer de manière sécurisée les mutations de données sur le serveur.
import type { NextApiRequest, NextApiResponse } from 'next'
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
const data = req.body
const id = await createItem(data)
res.status(200).json({ id })
}
export default function handler(req, res) {
const data = req.body
const id = await createItem(data)
res.status(200).json({ id })
}
Ensuite, appelez la route API depuis le client avec un gestionnaire d'événements :
import { FormEvent } from 'react'
export default function Page() {
async function onSubmit(event: FormEvent<HTMLFormElement>) {
event.preventDefault()
const formData = new FormData(event.currentTarget)
const response = await fetch('/api/submit', {
method: 'POST',
body: formData,
})
// Gérer la réponse si nécessaire
const data = await response.json()
// ...
}
return (
<form onSubmit={onSubmit}>
<input type="text" name="name" />
<button type="submit">Soumettre</button>
</form>
)
}
export default function Page() {
async function onSubmit(event) {
event.preventDefault()
const formData = new FormData(event.target)
const response = await fetch('/api/submit', {
method: 'POST',
body: formData,
})
// Gérer la réponse si nécessaire
const data = await response.json()
// ...
}
return (
<form onSubmit={onSubmit}>
<input type="text" name="name" />
<button type="submit">Soumettre</button>
</form>
)
}
Validation de formulaire
Nous recommandons d'utiliser la validation HTML comme required
et type="email"
pour une validation côté client de base.
Pour une validation côté serveur plus avancée, vous pouvez utiliser une bibliothèque de validation de schéma comme zod pour valider les champs du formulaire avant de muter les données :
import type { NextApiRequest, NextApiResponse } from 'next'
import { z } from 'zod'
const schema = z.object({
// ...
})
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
const parsed = schema.parse(req.body)
// ...
}
import { z } from 'zod'
const schema = z.object({
// ...
})
export default async function handler(req, res) {
const parsed = schema.parse(req.body)
// ...
}
Gestion des erreurs
Vous pouvez utiliser l'état React pour afficher un message d'erreur lorsqu'une soumission de formulaire échoue :
import React, { useState, FormEvent } from 'react'
export default function Page() {
const [isLoading, setIsLoading] = useState<boolean>(false)
const [error, setError] = useState<string | null>(null)
async function onSubmit(event: FormEvent<HTMLFormElement>) {
event.preventDefault()
setIsLoading(true)
setError(null) // Effacer les erreurs précédentes lorsqu'une nouvelle requête commence
try {
const formData = new FormData(event.currentTarget)
const response = await fetch('/api/submit', {
method: 'POST',
body: formData,
})
if (!response.ok) {
throw new Error('Échec de la soumission des données. Veuillez réessayer.')
}
// Gérer la réponse si nécessaire
const data = await response.json()
// ...
} catch (error) {
// Capturer le message d'erreur pour l'afficher à l'utilisateur
setError(error.message)
console.error(error)
} finally {
setIsLoading(false)
}
}
return (
<div>
{error && <div style={{ color: 'red' }}>{error}</div>}
<form onSubmit={onSubmit}>
<input type="text" name="name" />
<button type="submit" disabled={isLoading}>
{isLoading ? 'Chargement...' : 'Soumettre'}
</button>
</form>
</div>
)
}
import React, { useState } from 'react'
export default function Page() {
const [isLoading, setIsLoading] = useState(false)
const [error, setError] = useState(null)
async function onSubmit(event) {
event.preventDefault()
setIsLoading(true)
setError(null) // Effacer les erreurs précédentes lorsqu'une nouvelle requête commence
try {
const formData = new FormData(event.currentTarget)
const response = await fetch('/api/submit', {
method: 'POST',
body: formData,
})
if (!response.ok) {
throw new Error('Échec de la soumission des données. Veuillez réessayer.')
}
// Gérer la réponse si nécessaire
const data = await response.json()
// ...
} catch (error) {
// Capturer le message d'erreur pour l'afficher à l'utilisateur
setError(error.message)
console.error(error)
} finally {
setIsLoading(false)
}
}
return (
<div>
{error && <div style={{ color: 'red' }}>{error}</div>}
<form onSubmit={onSubmit}>
<input type="text" name="name" />
<button type="submit" disabled={isLoading}>
{isLoading ? 'Chargement...' : 'Soumettre'}
</button>
</form>
</div>
)
}
Affichage de l'état de chargement
Vous pouvez utiliser l'état React pour afficher un état de chargement lorsqu'un formulaire est en cours de soumission sur le serveur :
import React, { useState, FormEvent } from 'react'
export default function Page() {
const [isLoading, setIsLoading] = useState<boolean>(false)
async function onSubmit(event: FormEvent<HTMLFormElement>) {
event.preventDefault()
setIsLoading(true) // Définir le chargement à true lorsque la requête commence
try {
const formData = new FormData(event.currentTarget)
const response = await fetch('/api/submit', {
method: 'POST',
body: formData,
})
// Gérer la réponse si nécessaire
const data = await response.json()
// ...
} catch (error) {
// Gérer l'erreur si nécessaire
console.error(error)
} finally {
setIsLoading(false) // Définir le chargement à false lorsque la requête se termine
}
}
return (
<form onSubmit={onSubmit}>
<input type="text" name="name" />
<button type="submit" disabled={isLoading}>
{isLoading ? 'Chargement...' : 'Soumettre'}
</button>
</form>
)
}
import React, { useState } from 'react'
export default function Page() {
const [isLoading, setIsLoading] = useState(false)
async function onSubmit(event) {
event.preventDefault()
setIsLoading(true) // Définir le chargement à true lorsque la requête commence
try {
const formData = new FormData(event.currentTarget)
const response = await fetch('/api/submit', {
method: 'POST',
body: formData,
})
// Gérer la réponse si nécessaire
const data = await response.json()
// ...
} catch (error) {
// Gérer l'erreur si nécessaire
console.error(error)
} finally {
setIsLoading(false) // Définir le chargement à false lorsque la requête se termine
}
}
return (
<form onSubmit={onSubmit}>
<input type="text" name="name" />
<button type="submit" disabled={isLoading}>
{isLoading ? 'Chargement...' : 'Soumettre'}
</button>
</form>
)
}
Redirection
Si vous souhaitez rediriger l'utilisateur vers une route différente après une mutation, vous pouvez utiliser redirect
vers n'importe quelle URL absolue ou relative :
import type { NextApiRequest, NextApiResponse } from 'next'
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
const id = await addPost()
res.redirect(307, `/post/${id}`)
}
export default async function handler(req, res) {
const id = await addPost()
res.redirect(307, `/post/${id}`)
}
Définition de cookies
Vous pouvez définir des cookies dans une route API en utilisant la méthode setHeader
sur la réponse :
Lecture de cookies
Vous pouvez lire les cookies dans une route API en utilisant l'aide de requête cookies
:
Suppression de cookies
Vous pouvez supprimer des cookies dans une route API en utilisant la méthode setHeader
sur la réponse :