From a578a7d22cf5d299fb98ed3bde42d4973bb0d6cd Mon Sep 17 00:00:00 2001 From: matthieureynier Date: Thu, 25 Jun 2026 09:11:46 +0200 Subject: [PATCH] Services: correction Carte/likes (1 seule approche: likes dans le parent, total recalcule, fix syntaxe) + enonce React #3 (formulaire d'ajout, tri, React Router) --- CORRECTION_carte_likes.md | 115 ++++++++++++++++++++++++++ ENONCE_react_3_services.md | 164 +++++++++++++++++++++++++++++++++++++ 2 files changed, 279 insertions(+) create mode 100644 CORRECTION_carte_likes.md create mode 100644 ENONCE_react_3_services.md diff --git a/CORRECTION_carte_likes.md b/CORRECTION_carte_likes.md new file mode 100644 index 0000000..f876801 --- /dev/null +++ b/CORRECTION_carte_likes.md @@ -0,0 +1,115 @@ +# 🔧 Correction — pourquoi ton projet ne s'affiche plus + +Ton commit le dit bien : « + de bugs » 😅. Pas de panique, le diagnostic est simple : tu as **mĂ©langĂ© deux façons** de gĂ©rer les likes, et du coup `Carte.jsx` utilise des choses qui n'existent pas chez elle. + +--- + +## 🔍 Ce qui cloche dans `Carte.jsx` + +```jsx +import { useState } from "react"; +function Carte(props) { + return ( + ... + +``` + +Deux problĂšmes : +1. **Erreur de syntaxe** : ta fonction `() => { ... }` n'est jamais refermĂ©e par `)`. À elle seule, ça **empĂȘche l'app de s'afficher** (page blanche / erreur de build). +2. **`likes` et `setLikes` n'existent pas dans `Carte`** : tu as dĂ©placĂ© les likes dans le **parent** (`App` a bien `useState({...})`), donc `Carte` n'a plus de `useState`. Elle essaie d'utiliser des variables qui ne sont plus lĂ . + +> 🧠 **La cause de fond :** tu as commencĂ© l'approche « **les likes vivent dans le parent** » (bien !) mais tu as gardĂ© des bouts de l'ancienne approche « les likes dans la carte ». Il faut **choisir une seule** approche. On garde celle du parent (c'est celle de la correction prĂ©cĂ©dente). + +--- + +## ✅ La rĂšgle : `Carte` ne fait qu'**afficher** ce qu'on lui donne + +Dans l'approche « parent », la carte **n'a pas d'Ă©tat** : elle reçoit `likes` et `onLike` en **props**, c'est tout. + +### `Carte.jsx` corrigĂ© (remplace tout le fichier) +```jsx +function Carte(props) { + return ( +
+

{props.titre}

+

{props.niveaux}

+ +
+ ); +} + +export default Carte; +``` +> 🔎 Plus de `import { useState }`, plus de `setLikes`, **un seul** `

` (tu en avais deux : `titre` ET `nom`), et plus de `props.createur` inutile. La carte affiche `props.likes` et, au clic, appelle `props.onLike` — point. + +--- + +## ✅ CĂŽtĂ© `App.jsx` : finir l'approche « parent » + +Tu as encore l'**ancien** `total` mutĂ© qui traĂźne. On le supprime et on **recalcule** le total. + +```jsx +function App() { + const [likes, setLikes] = useState({}); // {} au dĂ©part (pas {1:3, 4:1}) + const [recherche, setRecherche] = useState(""); + // ❌ SUPPRIME : const [total, setTotal] = useState(0); + + // incrĂ©mente le like d'UNE trilogie (par son id) + function liker(id) { + setLikes((prev) => ({ ...prev, [id]: (prev[id] || 0) + 1 })); + } + + // le total se RECALCULE Ă  partir des likes + const total = Object.values(likes).reduce((s, n) => s + n, 0); + + const filtrees = trilogies.filter((t) => + t.nom.toLowerCase().includes(recherche.toLowerCase()) + ); + + return ( +
+
+ setRecherche(e.target.value)} + /> +

👍 Total de likes : {total}

+ {filtrees.length === 0 &&

Aucune trilogie trouvée

} + + {filtrees.map((trilo) => ( + liker(trilo.id)} // incrémente SON like + /> + ))} +
+
+ ); +} +``` + +**✅ Test :** l'app s'affiche de nouveau. Chaque carte montre son ❀, et le « Total de likes » = la somme, toujours juste. + +> 💡 **À retenir :** dans une appli React, **une donnĂ©e vit Ă  UN seul endroit**. Les likes vivent dans `App` ; `Carte` ne fait que les **afficher** (props) et **signaler** un clic (`onLike`). Ne mĂ©lange jamais « Ă©tat dans le parent » et « Ă©tat dans l'enfant » pour la mĂȘme donnĂ©e — c'est ce qui t'a mis dedans. + +--- + +## ✅ RĂ©cap + +- [ ] `Carte.jsx` : version « affichage seul » (props `titre`, `niveaux`, `likes`, `onLike`), un seul `

`, plus de `useState` +- [ ] `App.jsx` : supprimer l'ancien `total`, ajouter `liker(id)`, recalculer `total` avec `reduce` +- [ ] Tester : l'app s'affiche, likes par carte + total correct + +Quand c'est rĂ©parĂ©, tu peux passer Ă  **`ENONCE_react_3_services.md`** (la suite). 🚀 diff --git a/ENONCE_react_3_services.md b/ENONCE_react_3_services.md new file mode 100644 index 0000000..ec80a64 --- /dev/null +++ b/ENONCE_react_3_services.md @@ -0,0 +1,164 @@ +# 🎼 ÉnoncĂ© React #3 — formulaire, tri & plusieurs pages + +(À attaquer une fois ton projet rĂ©parĂ© via `CORRECTION_carte_likes.md`.) + +Tu sais maintenant : composants, props, Ă©tat local, **lifting state up**, `useEffect`. On monte d'un cran avec **3 nouveaux gros morceaux**. Comme avant : explications + mini-exemples, Ă  toi d'appliquer sur tes trilogies. + +| Module | Tu apprends | Niveau | +|---|---|---| +| I | **Formulaire d'ajout** : modifier une liste en state | ⭐⭐ | +| J | **Trier** la liste (select contrĂŽlĂ© + `sort`) | ⭐⭐ | +| K | **Plusieurs pages** avec React Router | ⭐⭐⭐ | + +--- + +## 📝 Module I — Ajouter une trilogie via un formulaire + +### I.1 — D'abord, rendre la liste **modifiable** +Aujourd'hui `trilogies` est un `const` figĂ©. Pour pouvoir **ajouter**, il doit devenir un **Ă©tat** : +```jsx +const donneesInitiales = [ /* tes 5 trilogies */ ]; + +function App() { + const [trilogies, setTrilogies] = useState(donneesInitiales); + // ... +} +``` + +### I.2 — Un formulaire contrĂŽlĂ© +```jsx +const [nom, setNom] = useState(""); +const [niveaux, setNiveaux] = useState(""); + +function ajouter(e) { + e.preventDefault(); // empĂȘche le rechargement de page + if (nom.trim() === "") return; // on n'ajoute pas du vide + const nouvelle = { id: Date.now(), nom, niveaux }; // id unique simple + setTrilogies([...trilogies, nouvelle]); // 👈 NOUVEAU tableau = ancien + la nouvelle + setNom(""); // on vide les champs + setNiveaux(""); +} + +return ( +
+ setNom(e.target.value)} placeholder="Nom de la trilogie" /> + setNiveaux(e.target.value)} placeholder="Niveaux" /> + +
+); +``` + +> đŸ§© **Le point clĂ© :** on ne « pousse » pas dans le tableau existant (`trilogies.push(...)` ❌). On crĂ©e un **nouveau tableau** avec `[...trilogies, nouvelle]` et on le donne Ă  `setTrilogies`. React ne rĂ©affiche que si on lui passe une **nouvelle** valeur. C'est la rĂšgle de l'**immutabilitĂ©** : on remplace, on ne modifie pas sur place. + +**✅ Test :** remplis le formulaire, clique « Ajouter » → la carte apparaĂźt en bas, les champs se vident, la page ne recharge pas. + +> 🚀 Bonus : un bouton « đŸ—‘ïž Supprimer » sur chaque carte → `setTrilogies(trilogies.filter((t) => t.id !== id))` (un nouveau tableau **sans** celle-lĂ ). + +--- + +## 🔀 Module J — Trier la liste + +Un ` setTri(e.target.value)}> + + + + {affichees.map((trilo) => ( /* ... ta Carte ... */ ))} + +); +``` + +> 🔎 `[...trilogies]` = une **copie** (pour ne pas modifier l'original avec `sort`). Et tu combines avec ton **filtre** de recherche : on filtre **puis** on trie **puis** on `.map()`. + +**✅ Test :** change le tri → l'ordre des cartes change. + +--- + +## 🧭 Module K — Plusieurs pages avec React Router + +Jusqu'ici tu as **une seule page**. Pour avoir une page **dĂ©tail** par trilogie (avec ses niveaux, son nombre de likes
), on utilise **React Router**. + +### K.1 — Installer +Dans le terminal, dans le dossier du projet : +```bash +npm install react-router-dom +``` + +### K.2 — Envelopper l'app (dans `main.jsx`) +```jsx +import { BrowserRouter } from "react-router-dom"; + +createRoot(document.getElementById("root")).render( + + + +); +``` + +### K.3 — DĂ©finir les routes (dans `App.jsx`) +```jsx +import { Routes, Route } from "react-router-dom"; + +function App() { + return ( + + } /> + } /> + + ); +} +``` +- `path="/"` → ta page d'accueil (la liste). +- `path="/trilogie/:id"` → une page **dynamique** : le `:id` change selon la trilogie. + +### K.4 — Des liens (au lieu de ``) +Dans ta `Carte`, un lien vers le dĂ©tail : +```jsx +import { Link } from "react-router-dom"; + +Voir les dĂ©tails +``` +> 🔎 `` navigue **sans recharger** la page (c'est tout l'intĂ©rĂȘt d'une « single page app »). `` rechargerait tout. + +### K.5 — Lire l'id dans la page dĂ©tail +```jsx +import { useParams } from "react-router-dom"; + +function Detail() { + const { id } = useParams(); // rĂ©cupĂšre le :id de l'URL + // retrouve la bonne trilogie par son id, et affiche-la + return

Détails de la trilogie {id}

; +} +``` + +**✅ Test :** clique « Voir les dĂ©tails » sur une carte → l'URL devient `/trilogie/3` et la page dĂ©tail s'affiche, **sans rechargement**. Le bouton « prĂ©cĂ©dent » du navigateur te ramĂšne Ă  la liste. + +> đŸ§© **Les 4 briques de React Router :** `` (enveloppe), `/` (quelle page pour quelle URL), `` (naviguer), `useParams()` (lire un morceau dynamique de l'URL). C'est la base de **tous** les sites multi-pages en React. + +--- + +## ✅ Checklist +- [ ] I — liste en `useState` + formulaire d'ajout (immutabilitĂ© avec `[...]`) +- [ ] J — tri via un `