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:
@@ -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.
|
||||
Reference in New Issue
Block a user