Tuto contact: faire remonter les likes (l'enfant doit APPELER props.onLike) + explication de l'initialisation useState (pourquoi meme valeur de depart)

This commit is contained in:
2026-06-24 14:47:13 +02:00
parent 6be5ca583b
commit f74f9a0100
+109
View File
@@ -0,0 +1,109 @@
# 🧩 Tuto pas à pas — le parent qui additionne les likes des enfants
Tu cherches à faire **remonter** les likes : chaque `Carte` a son compteur, et `App` (le parent) affiche le **total**. C'est exactement le bon objectif 👍. Il te manque **une seule ligne** — et je veux surtout que tu comprennes **pourquoi**.
---
## 🔍 D'abord, pourquoi ton total reste à 0
Regarde le bouton dans ta `Carte` :
```jsx
<button onClick={() => setLikes(likes + 1)}> {likes}</button>
```
Quand on clique, tu fais `setLikes(likes + 1)` → ça met à jour **le compteur de la carte**. ✅
Mais… tu n'as **jamais** prévenu le parent ! La fonction `onLike` que `App` t'a donnée en prop n'est **jamais appelée**. Donc `App` ne sait pas qu'on a liké → `total` reste à 0.
> 🧠 **L'idée à comprendre :** un enfant **ne peut pas** modifier directement l'état du parent. Le parent lui **prête une fonction** (`onLike`), et l'enfant doit **l'appeler** au bon moment. C'est l'enfant qui dit « hé, on m'a likée ! » — le parent décide quoi en faire.
---
## 🪜 La correction, étape par étape
### Étape 1 — le parent a déjà tout (rien à changer)
Dans `App.jsx`, tu as déjà :
```jsx
const [total, setTotal] = useState(0);
// ...
<Carte ... onLike={() => setTotal((t) => t + 1)} />
// ...
<p>Total de likes : {total}</p>
```
Le parent tient le `total` et passe une fonction `onLike` à **chaque** carte. ✅
### Étape 2 — l'enfant doit APPELER `onLike` (la ligne qui manque)
Dans `Carte`, le bouton doit faire **deux choses** au clic : augmenter **son** compteur **et** prévenir le parent.
```jsx
<button
onClick={() => {
setLikes(likes + 1); // 1) j'augmente MON compteur (état de la carte)
props.onLike(); // 2) je préviens le PARENT (sa fonction)
}}
>
{likes}
</button>
```
> 🔎 Deux instructions dans le `onClick` → on les met entre accolades `{ ... }` avec un `;` entre les deux. C'est une petite fonction qui fait deux choses à la suite.
**✅ Test :** clique sur le ❤️ d'une carte → **son** compteur monte **et** le « Total de likes » en haut monte aussi. Clique sur une autre carte → le total continue de grimper.
---
## 🎓 Ta question : pourquoi chaque bouton démarre avec la **même** valeur ?
C'est une **excellente** question, et la réponse, c'est **l'initialisation** de `useState`.
```jsx
const [likes, setLikes] = useState(
() => Number(localStorage.getItem("likes-" + props.id)) || 0
);
```
### 1. La valeur dans `useState(...)` n'est qu'un **point de départ**
L'argument que tu passes à `useState(...)` est la **valeur initiale** : React l'utilise **une seule fois**, au tout **premier affichage** de la carte, pour démarrer le compteur. Ensuite, c'est `setLikes(...)` qui prend le relais — l'initialisation **ne sert plus**.
> 🧠 `useState(valeurDeDépart)` = « démarre à cette valeur, **la première fois seulement** ». Après, l'état vit sa vie.
### 2. Chaque `<Carte>` est **indépendante** (elle ne partage rien)
Chaque fois que tu écris `<Carte />`, React crée une **instance séparée**, avec son **propre** `likes`. Liker la carte n°1 ne touche pas la carte n°2 : ce sont des compteurs distincts.
### 3. Alors pourquoi elles affichent toutes la même valeur au départ ?
Parce qu'elles exécutent toutes **le même calcul d'initialisation**, et qu'au **premier lancement**, `localStorage` est **vide** :
- `localStorage.getItem("likes-" + props.id)` → renvoie `null` (rien n'est encore stocké)
- `Number(null)``0`, donc `|| 0`**0**
**toutes** les cartes démarrent à **0**. Ce n'est pas qu'elles « partagent » une valeur : c'est qu'elles **partent toutes de la même situation** (rien en mémoire). C'est comme 4 personnes qui commencent un jeu : elles ont toutes 0 point au début, mais chacune marque ses propres points ensuite.
> 💡 **La preuve que c'est bien indépendant et par-carte :** like la carte n°1, **recharge la page (F5)**. La carte n°1 retrouve **sa** valeur (lue dans `localStorage` à la clé `likes-1`), les autres restent à 0. Chaque carte a donc bien **sa propre** initialisation, basée sur **son** `id`.
---
## ⚠️ Un piège que tu as déjà senti (commit « buggy »)
Tu as remarqué : les likes par carte **survivent au rechargement** (ils sont dans `localStorage`), **mais le `total` repart à 0** après un F5. Normal : le `total` du parent n'est **pas** stocké, et il n'est pas **recalculé** à partir des cartes — il ne fait que s'incrémenter aux clics.
Pour l'instant, **c'est OK** : ton objectif était de faire **remonter** un like vers le parent (le pattern callback ci-dessus), et c'est réussi.
> 🔭 Pour aller plus loin (plus tard) : il existe une version plus robuste où le **total se recalcule** tout seul à partir des likes (une seule « source de vérité »). On en reparlera — c'est l'étape d'après.
---
## 🧹 Petit nettoyage
Dans `Carte`, tu as un effet **vide** qui ne sert à rien :
```jsx
useEffect(() => {}, [likes]); // ❌ à supprimer
```
Enlève-le, il ne fait rien.
---
## ✅ Récap
- Le parent **prête** une fonction (`onLike`) ; l'enfant doit **l'appeler** → c'est la ligne `props.onLike()` qui te manquait.
- Au clic : l'enfant met à jour **son** état **et** appelle `props.onLike()`.
- `useState(x)` = valeur de départ, utilisée **une fois**. Chaque carte est **indépendante** ; elles démarrent toutes pareil parce qu'au premier lancement la mémoire est vide (toutes à 0).
- Supprime le `useEffect` vide.