Les classiques des composants React
Exercice 0
Vous allez faire tous les exercices sur le même projet React, pour chaque exercice, créez le composant dans un fichier .jsx séparé et appelez le dans le composant App.
Créez un repository public avec un README sur GitHub, appelez-le bre05-react-soutien
Clonez-le dans le dossier sites/react de votre IDE.
Dans le dossier bre05-react-soutien:
Créez un projet appelé soutien avec npm-create-vite
Videz le fichier src/index.css
Remplacez le code du fichier App.css avec le code suivant :
:root {
--primary: #646cff;
--bg: #f9f9f9;
--text: #213547;
--border: #ddd;
--white: #ffffff;
}
body {
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
background-color: var(--bg);
color: var(--text);
padding: 2rem;
}
.exercise-container {
max-width: 600px;
margin: 2rem auto;
padding: 1.5rem;
background: var(--white);
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
button {
background-color: var(--primary);
color: white;
border: none;
padding: 0.6rem 1.2rem;
border-radius: 4px;
cursor: pointer;
transition: opacity 0.2s;
}
button:hover {
opacity: 0.8;
}
button:disabled {
background-color: #ccc;
cursor: not-allowed;
}
input[type="text"], select, textarea {
width: 100%;
padding: 8px;
margin: 10px 0;
border: 1px solid var(--border);
border-radius: 4px;
box-sizing: border-box;
}
/* Utilitaires pour les onglets et listes */
.flex-row { display: flex; gap: 10px; margin-bottom: 1rem; }
.hidden { display: none; }
.active-tab { border-bottom: 3px solid var(--primary); font-weight: bold; }
Exercice 1 : ReadMore
Voici le code HTML de votre composant :
<div class="exercise-container">
<img src="https://images.unsplash.com/photo-1507525428034-b723cf961d3e?auto=format&fit=crop&w=600&q=80" alt="Plage" style="width:100%; border-radius:4px; margin-bottom:1rem;"/>
<h2>Les trésors cachés de Bali</h2>
<p>
Bali, l'île des Dieux, offre bien plus que ses plages célèbres. Entre les rizières en terrasse d'Ubud et les temples sacrés nichés sur les falaises d'Uluwatu, chaque recoin raconte une histoire.
<span class="content-extra">
Ne manquez pas la cascade de Sekumpul, souvent oubliée des touristes, qui nécessite une randonnée de 40 minutes mais offre un spectacle naturel époustouflant au lever du soleil.
</span>
</p>
<button>Lire la suite</button>
</div>
Situation de départ du ReadMore:
Un titre, une image et un premier paragraphe sont visibles. Un second paragraphe (.content-extra) est présent dans le code.
Objectif du ReadMore :
Créez un état isVisible (initialisé à false).
Utilisez cet état pour afficher ou masquer le second paragraphe (rendu conditionnel).
Action : Au clic sur le bouton, l'état isVisible doit passer à true.
Dynamisme : Si isVisible est vrai, le texte du bouton doit devenir "Réduire", sinon il affiche "Lire la suite".
Exercice 2 : Onglets
Voici le code HTML de votre composant :
<div class="exercise-container">
<div class="flex-row">
<button class="active-tab">Description</button>
<button>Spécifications</button>
<button>Avis (12)</button>
</div>
<div class="tab-content">
<p>Le nouveau Casque <strong>NovaSound X1</strong> redéfinit l'excellence audio. Équipé de haut-parleurs en néodyme de 40 mm, il offre une clarté exceptionnelle des aigus et des basses profondes.</p>
<p>Sa technologie de réduction de bruit active (ANC) analyse le bruit ambiant 1000 fois par seconde pour vous isoler parfaitement, que vous soyez dans le métro ou dans un bureau open-space.</p>
</div>
<div class="tab-content">
<ul style="list-style: none; padding: 0;">
<li style="margin-bottom: 8px;"><strong>Autonomie :</strong> 40h (ANC activé) / 55h (Standard)</li>
<li style="margin-bottom: 8px;"><strong>Poids :</strong> 250g (Design ultra-léger)</li>
<li style="margin-bottom: 8px;"><strong>Connectivité :</strong> Bluetooth 5.2 et Jack 3.5mm</li>
<li style="margin-bottom: 8px;"><strong>Charge :</strong> USB-C (10 min = 5h d'écoute)</li>
</ul>
</div>
<div class="tab-content">
<div style="border-left: 3px solid var(--primary); padding-left: 15px; margin-bottom: 15px;">
<p style="margin: 0; font-weight: bold;">⭐⭐⭐⭐⭐ - Sophie L.</p>
<p style="margin: 5px 0; font-style: italic;">"Le confort est incroyable, même après 4h de visio. Le son est très équilibré."</p>
</div>
<div style="border-left: 3px solid var(--primary); padding-left: 15px;">
<p style="margin: 0; font-weight: bold;">⭐⭐⭐⭐ - Marc K.</p>
<p style="margin: 5px 0; font-style: italic;">"Excellente réduction de bruit. Un peu cher, mais la qualité est là."</p>
</div>
</div>
</div>
Situation de départ des onglets
Trois boutons en haut et une zone de contenu en bas.
Objectif des onglets :
Créez un état currentTab (initialisé à "description").
Associez chaque bouton à une valeur : "description", "specs", "avis".
Action : Au clic sur un bouton, mettez à jour currentTab avec la valeur correspondante.
Rendu : Affichez le bloc HTML de la description SI currentTab est égal à "description", et ainsi de suite pour les autres.
Style : Appliquez la classe CSS active-tab au bouton uniquement si son nom correspond à l'état currentTab.
Voici le code HTML de votre composant :
<div class="exercise-container">
<h3>Inscription au Meetup React</h3>
<label>Régime alimentaire :</label>
<select>
<option value="none">Sans restriction</option>
<option value="vege">Végétarien</option>
<option value="vegan">Végétalien</option>
<option value="autre">Autre (Allergies...)</option>
</select>
<div class="conditional-field">
<label>Merci de préciser vos allergies :</label>
<textarea placeholder="Ex: Arachides, Gluten..."></textarea>
</div>
<button style="margin-top:1rem; width:100%;">Confirmer l'inscription</button>
</div>
Un menu déroulant (<select>) avec plusieurs options, dont une valeur "autre".
Créez un état choice pour stocker la valeur sélectionnée du <select>.
Liez cet état au champ avec l'attribut value et l'événement onChange.
Condition : Le champ <textarea> (précisions) ne doit s'afficher dans le DOM que SI choice === "autre".
Exercice 4 Champ de recherche
Voici le code HTML de votre composant :
<div class="exercise-container">
<h3>Annuaire de l'équipe</h3>
<input type="text" placeholder="Rechercher un collaborateur (ex: 'Alice' ou 'Dev')..." />
<ul style="list-style: none; padding: 0;">
<li style="padding: 10px; border-bottom: 1px solid #eee;">
<strong>Alice Martin</strong> - <small>Lead Développeuse</small>
</li>
<li style="padding: 10px; border-bottom: 1px solid #eee;">
<strong>Bob Durand</strong> - <small>UX Designer</small>
</li>
<li style="padding: 10px; border-bottom: 1px solid #eee;">
<strong>Charlie Leroy</strong> - <small>Product Manager</small>
</li>
</ul>
</div>
Les données de l'exercice :
const users = [
{ id: 1, name: "Alice Martin", role: "Lead Développeuse" },
{ id: 2, name: "Bob Durand", role: "UX Designer" },
{ id: 3, name: "Charlie Leroy", role: "Product Manager" },
{ id: 4, name: "Diane Petit", role: "Développeuse Front-end" }
];
Situation de départ du champ de recherche
Un tableau d'objets users (fourni) et un champ de texte.
Objectif du champ de recherche
Créez un état searchTerm (initialisé par une chaîne vide "").
Liez cet état à l'input de recherche (value et onChange).
Logique : Créez une variable temporaire qui filtre le tableau users : ne gardez que les utilisateurs dont le nom contient les lettres de searchTerm.
Rendu : Utilisez .map() sur ce tableau filtré pour générer les <li>.
Exercice 5 : Billetterie
Le HTML de votre composant :
<div class="exercise-container">
<div style="display: flex; justify-content: space-between; align-items: center;">
<div>
<h3 style="margin:0;">Billet Adulte</h3>
<p style="color: #666; margin: 5px 0;">Exposition "L'Art de demain" - 15€</p>
</div>
<div class="flex-row" style="align-items: center;">
<button> - </button>
<span style="min-width: 30px; text-align: center; font-weight: bold;">1</span>
<button> + </button>
</div>
</div>
<hr style="border: 0; border-top: 1px solid #eee; margin: 15px 0;" />
<div style="text-align: right;">
<strong>Total : 15€</strong>
</div>
</div>
Situation de départ de la billetterie
Un prix fixe (15€), un bouton -, un bouton +, et un affichage de la quantité.
Objectif de la billetterie
Créez un état quantity (initialisé à 1).
Actions : Le bouton + augmente la quantité de 1. Le bouton - la diminue de 1.
Contraintes :
Calcul : Affichez le total en multipliant en direct : {quantity * 15}€.
06 February 2026