Boutique en ligne pédagogique pour mettre en œuvre les hooks React fondamentaux :
useState · useEffect · useContext · useCallback · useMemo · hooks personnalisés.
git clone https://github.com/<organisation>/react-shop-tp.git
cd react-shop-tpnpm installnpm run devOuvrir http://localhost:5173 dans le navigateur.
Vous devez voir la NavBar « React Shop », une zone principale vide et le Footer.
À la fin de chaque étape, effectuer un commit avec le message indiqué.
À la fin du TP, pousser votre travail sur la branche main :
git push origin mainPour chaque question ci-dessous, compléter ce fichier README.md avec votre réponse : capture d'écran, extrait de code ou explication.
Remplacer les blocs<!-- RÉPONSE -->par votre contenu.
Fichier à modifier : src/App.jsx
Remplacer les trois variables figées par de vrais appels useState, puis câbler
les callbacks onSearchChange, onCartClick, onPageChange et onClose.
Commit : step1: wire App state with useState
Expliquer en 2-3 phrases le rôle de useState et pourquoi React nécessite ce
hook plutôt qu'une simple variable JavaScript.
Coller ici l'extrait de code correspondant aux trois déclarations d'état dans App.jsx.
// RÉPONSE Q1.2 — vos trois useState iciCliquer sur le bouton « Panier » puis sur « Fermer ».
Joindre une capture montrant la modale ouverte (panier vide).
Fichiers à modifier : src/components/ProductCard/ProductCard.jsx
et src/components/ProductList/ProductList.jsx
- Dans
ProductCard, câbler leonClickdu bouton « Ajouter au panier ». - Dans
ProductList, remplacer le texte TODO par la grille Bootstrap deProductCard.
Pour tester sans l'API, utiliser ces données fictives dans
ProductList:const products = [ { id: 1, title: 'Produit test', price: 9.99, thumbnail: 'https://placehold.co/300x200', rating: 4.5 } ]
Commit : step2: render ProductCard with Add to Cart
Expliquer en 2-3 phrases. Pourquoi pose-t-il problème quand l'arbre de composants est profond ?
Coller ici la partie JSX du .map() dans ProductList.
// RÉPONSE Q2.2 — votre map iciFichier à modifier : src/hooks/useProducts.js
et src/components/ProductList/ProductList.jsx (brancher le hook + Pagination)
Implémenter useProducts(searchQuery, page) qui récupère les produits depuis :
https://dummyjson.com/products?limit=12&skip=N(navigation)https://dummyjson.com/products/search?q=MOT&limit=12&skip=N(recherche)
Commit : step3: fetch products with useEffect, pagination
Expliquer pourquoi on ne peut pas placer un fetch() directement dans le corps
du composant (ou du hook). Quel problème cela provoquerait-il ?
Que se passerait-il si ce tableau était vide [] ?
Et si on l'omettait complètement ?
// RÉPONSE Q3.3 — votre useEffect iciJoindre une capture montrant la page 2 chargée.
Fichier à modifier : src/hooks/useDebounce.js et src/App.jsx
Implémenter useDebounce(value, delay) puis l'utiliser dans App.jsx :
const debouncedQuery = useDebounce(searchQuery, 400)Passer debouncedQuery (et non searchQuery) à ProductList.
Commit : step4: add useDebounce custom hook
Décrire ce qui se passerait sans debounce quand l'utilisateur tape rapidement.
Expliquer pourquoi return () => clearTimeout(timer) est indispensable dans ce cas précis.
// RÉPONSE Q4.3 — useDebounce completOuvrir l'onglet Réseau du navigateur, taper rapidement « phone » lettre par lettre. Joindre une capture montrant qu'une seule requête est envoyée après la pause.
Fichiers à modifier : src/hooks/useCart.js et src/context/CartContext.jsx
Implémenter useCart() avec :
useStatepour l'état du panier (initialisé depuislocalStorage)useEffectpour synchroniser le panier verslocalStorageaddToCart,removeFromCart,clearCartavecuseCallbackcartCountetcartTotalavecuseMemo
Puis brancher useCart() dans CartContext.jsx.
Commit : step5: implement useCart with localStorage
Quel problème survient si ces fonctions sont recréées à chaque rendu ? En quoi cela est-il particulièrement problématique quand elles sont passées via un contexte ?
Quelle est la différence entre useMemo et useCallback ?
Attention : si le produit est déjà dans le panier, incrémenter la quantité plutôt que d'ajouter un doublon.
// RÉPONSE Q5.3 — addToCart avec useCallbackAjouter 2-3 produits, rafraîchir la page (F5), vérifier que le panier est restauré.
Joindre une capture de l'onglet Application > localStorage dans les DevTools.
Fichiers à modifier :
src/components/NavBar/NavBar.jsx— badge du paniersrc/components/ProductList/ProductList.jsx—addToCartsrc/components/CartModal/CartModal.jsx— affichage, suppression, vidage
Commit : step6: consume CartContext in components
Tracer le chemin qu'aurait dû suivre addToCart sans contexte (de App jusqu'à ProductCard).
Comparer avec le chemin avec useContext.
// RÉPONSE Q6.2 — destructuration depuis useCartContext()Coller ici le JSX d'un <li> de la liste, avec le titre, la quantité, le prix et le bouton supprimer.
// RÉPONSE Q6.3 — JSX d'un article du panierAjouter au moins 2 produits différents (dont un en double), ouvrir la modale.
Joindre une capture montrant : le badge correct sur le bouton, les articles listés
avec leurs quantités et le total affiché.
Vérifier l'ensemble des fonctionnalités et soigner les cas limites.
Commit : step7: polish and final verification
Cocher chaque case après vérification :
- La recherche est débouncée (une seule requête après 400 ms de pause)
- La pagination fonctionne en mode navigation (sans recherche)
- Ajouter le même produit deux fois → la quantité s'incrémente (pas de doublon)
- Le panier est restauré après rafraîchissement de la page (F5)
- Le badge de la NavBar affiche le nombre total d'articles correct
- La suppression d'un article met à jour le badge et le total
- « Vider le panier » vide la liste et le localStorage
- Le total affiché dans la modale est correct
Joindre une capture de l'application complète et fonctionnelle (grille de produits visible, badge du panier non nul).
| Hook | Fichier(s) | Rôle |
|---|---|---|
useState |
App.jsx, useProducts.js, useCart.js, useDebounce.js |
Gérer les états locaux |
useEffect |
useProducts.js, useCart.js, useDebounce.js |
Effets de bord (fetch, localStorage, timer) |
useContext |
NavBar.jsx, ProductList.jsx, CartModal.jsx |
Consommer le contexte panier |
useCallback |
useCart.js |
Mémoriser les fonctions du panier |
useMemo |
useCart.js |
Calculer cartCount et cartTotal |






