Comment effectuer une mutation côté serveur

Apprends à modifier des données côté serveur avec React Router 7 et la méthode action : ajout, édition, suppression d’utilisateurs, et protection des données sensibles.

4 min read
Déverrouillez votre potentiel

avec React Router 7

Vous en avez marre de...

❌ perdre du temps à chercher des informations éparpillées
❌ ne pas avoir de retour sur votre progression
Assistant IA spécialisé

Posez vos questions 24/7 à notre IA experte en React Router 7

Quiz interactifs

Validez vos acquis avec des quiz personnalisés et un feedback instantané

🎁 Accès gratuit à cette leçon

Entrez votre email pour débloquer cette leçon gratuite

Dans cette leçon, on va apprendre à modifier des données — ajouter, éditer ou supprimer un utilisateur — côté serveur avec React Router 7. On verra comment :

  • Protéger les données confidentielles et éviter de les exposer côté client
  • Déclarer une action pour recevoir et traiter un formulaire en POST
  • Comprendre le cycle loader ⇒ action ⇒ loader pour garder l’UI synchronisée

Qu’est-ce qu’une mutation ?

Une mutation est une opération qui modifie l’état de ton application ou de ta base de données. Par opposition au loader (qui ne lit que des données), l’action va :

  1. Créer un nouvel enregistrement
  2. Modifier un enregistrement existant
  3. Supprimer un enregistrement

Comme on touche à la source de vérité (la DB), ce traitement doit absolument se faire côté serveur pour :

  • Protéger les données confidentielles
  • Appliquer des règles d’autorisation (ex : seul l’admin peut supprimer un utilisateur)

Déclarer une action dans ta route

Dans React Router 7, on ajoute simplement une fonction action exportée depuis le même fichier que le loader. Exemple minimal :

app/routes/users.tsx
1
import { Form, useLoaderData, type ActionFunctionArgs }
2
from 'react-router';
3
import { getUsers, addUser } from '~/users.server';
4
5
export async function loader() {
6
return { users: await getUsers() };
7
}
8
9
export async function action({ request }: ActionFunctionArgs) {
10
// 1. lire le payload du formulaire
11
const formData = await request.formData() // ^? FormData API
12
// 2. extraire la donnée
13
const name = formData.get('name') as string
14
// @callout: formData.get peut retourner null si le champ n'existe pas
15
// 3. modifier la DB
16
await addUser({ name })
17
// 4. renvoyer un signe de succès
18
return { ok: true }
19
}
20
21
export default function Users() {
22
const { users } = useLoaderData<typeof loader>()
23
return (
24
<>
25
{/* liste des utilisateurs */}
26
{/* ... */}
27
<Form method="POST">
28
<input name="name" placeholder="Nom d’utilisateur" />
29
<button type="submit">Ajouter</button>
30
</Form>
31
</>
32
)
33
}

Pourquoi Form et method="POST" ?

  • Par défaut un <form> HTML utilise la méthode GET ⇒ déclenche le loader.
  • Avec method="POST", React Router appelle d’abord ton action puis relance le loader pour mettre à jour l’UI.

Le composant <Form> de React Router

React Router fournit un <Form> amélioré :

app/routes/users.tsx
1
<Form method="POST" className="flex gap-2">
2
<input
3
type="text"
4
name="name"
5
className="border px-2"
6
placeholder="Nom d'utilisateur"
7
/>
8
<button type="submit" className="bg-blue-600 text-white px-4">
9
Ajouter un utilisateur
10
</button>
11
</Form>
  • Gestion automatique du chargement optimisé
  • Possibilité d’annuler la requête
  • Recharge partielle ou complète selon ta config

Code serveur : base de données en mémoire

Pour cet exemple, on simule une DB en mémoire dans app/users.server.ts :

app/users.server.ts
1
const db = {
2
users: [
3
{ id: 1, name: 'Virgile' },
4
{ id: 2, name: 'Robert' },
5
]
6
}
7
8
export async function getUsers() {
9
await new Promise(r => setTimeout(r, 100))
10
return db.users
11
}
12
13
export async function addUser({ name }: { name: string }) {
14
const newUser = { id: db.users.length + 1, name }
15
db.users.push(newUser)
16
return newUser
17
}

Attention : à chaque redémarrage du serveur, la mémoire est réinitialisée !
Pour la prod, migre vers une vraie base de données (PostgreSQL, MongoDB, …).


Cycle de vie loader ⇆ action

  1. Chargement initial
    • loader() read
    • render de ton composant
  2. Soumission du formulaire
    • action() write
    • relance de loader() read
    • re-render
  3. Résultat
    • L’UI est toujours en phase avec la DB
1
flowchart LR
2
load[Page load] -->|GET| loader
3
loader --> UI[Render UI]
4
UI -->|POST form| action
5
action --> loader
6
loader --> UI

C’est le principe du full-stack data avec React Router.


Points clés

  • Une mutation se fait toujours côté serveur
  • Déclare export async function action dans ta route
  • <Form method="POST"> déclenche l’action
  • Récupère formData depuis request
  • Retourne un JSON ou redirige (redirect('/users'))
  • Après l’action, le loader se relance et rafraîchit l’UI

Exercices rapides

  1. Supprimer un utilisateur

    • Ajoute un bouton « Supprimer » à chaque ligne de la liste
    • Envoie un formulaire POST avec name="_method" value="delete"
    • Implémente action pour détecter _method === 'delete'
  2. Éditer un utilisateur

    • Sur clic, affiche un champ <input> prérempli
    • Envoie id + name au action
    • Mets à jour db.users avec la nouvelle valeur
  3. Sécuriser l’action

    • Simule une vérification d’admin dans action
    • Si non autorisé, renvoie throw new Response("Forbidden", { status: 403 })
    • Affiche un message d’erreur dans ErrorBoundary

↩︎ Pour approfondir la gestion des formulaires et de la validation, consulte le module Formulaires avancés.

Premium
Quiz interactif
Testez vos connaissances et validez votre compréhension du module avec notre quiz interactif.
1

Comprendre les concepts fondamentaux

Quelle est la principale différence entre les composants client et serveur dans React ?

Les composants client s'exécutent uniquement dans le navigateur
Les composants serveur peuvent utiliser useState
Les composants client sont plus rapides
Il n'y a aucune différence significative
2

Optimisation des performances

Quelle technique est recommandée pour éviter les rendus inutiles dans React ?

Utiliser React.memo pour les composants fonctionnels
Ajouter plus d'états locaux
Éviter d'utiliser les props
Toujours utiliser les class components
3

Architecture des données

Quel hook permet de gérer les effets de bord dans un composant React ?

useEffect
useState
useMemo
useContext
4

Gestion des erreurs

Comment implémenter la gestion des erreurs pour les requêtes API dans React ?

Utiliser try/catch avec async/await
Ignorer les erreurs
Toujours afficher un message d'erreur
Rediriger l'utilisateur
5

Déploiement et CI/CD

Quelle est la meilleure pratique pour déployer une application React en production ?

Utiliser un service CI/CD comme GitHub Actions
Copier les fichiers manuellement via FTP
Envoyer le code source complet
Ne jamais mettre à jour l'application

Débloquez ce quiz et tous les autres contenus premium en achetant ce cours