Files
stagiaire/TUTO_total_likes.md
T

5.4 KiB

🧩 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 :

<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à :

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.

<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.

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 || 00

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 :

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.