Consignes du mini-projet
Dans ce mini-projet, vous allez devoir utiliser ce que vous avez appris en React pour créer un site qui permet d'afficher des recettes de cuisine que vous récupérez depuis une API.
Les notions que vous allez devoir utiliser sont les suivantes :
Composants React
Syntaxe JSX
Props
Fetch
useEffect
useReducer
l'API
Voici l'URL de l'API : https://dummyjson.com/recipes?limit=9.
Elle vous renvoie 9 recettes de cuisine au format suivant (en JSON) :
{
"recipes": [
{
"id": 1,
"name": "Classic Margherita Pizza",
"ingredients": [
"Pizza dough",
"Tomato sauce",
"Fresh mozzarella cheese",
"Fresh basil leaves",
"Olive oil",
"Salt and pepper to taste"
],
"instructions": [
"Preheat the oven to 475°F (245°C).",
"Roll out the pizza dough and spread tomato sauce evenly.",
"Top with slices of fresh mozzarella and fresh basil leaves.",
"Drizzle with olive oil and season with salt and pepper.",
"Bake in the preheated oven for 12-15 minutes or until the crust is golden brown.",
"Slice and serve hot."
],
"prepTimeMinutes": 20,
"cookTimeMinutes": 15,
"servings": 4,
"difficulty": "Easy",
"cuisine": "Italian",
"caloriesPerServing": 300,
"tags": [
"Pizza",
"Italian"
],
"userId": 166,
"image": "https://cdn.dummyjson.com/recipe-images/1.webp",
"rating": 4.6,
"reviewCount": 98,
"mealType": [
"Dinner"
]
},
{
"id": 2,
"name": "Vegetarian Stir-Fry",
"ingredients": [
"Tofu, cubed",
"Broccoli florets",
"Carrots, sliced",
"Bell peppers, sliced",
"Soy sauce",
"Ginger, minced",
"Garlic, minced",
"Sesame oil",
"Cooked rice for serving"
],
"instructions": [
"In a wok, heat sesame oil over medium-high heat.",
"Add minced ginger and garlic, sauté until fragrant.",
"Add cubed tofu and stir-fry until golden brown.",
"Add broccoli, carrots, and bell peppers. Cook until vegetables are tender-crisp.",
"Pour soy sauce over the stir-fry and toss to combine.",
"Serve over cooked rice."
],
"prepTimeMinutes": 15,
"cookTimeMinutes": 20,
"servings": 3,
"difficulty": "Medium",
"cuisine": "Asian",
"caloriesPerServing": 250,
"tags": [
"Vegetarian",
"Stir-fry",
"Asian"
],
"userId": 143,
"image": "https://cdn.dummyjson.com/recipe-images/2.webp",
"rating": 4.7,
"reviewCount": 26,
"mealType": [
"Lunch"
]
},
{
"id": 3,
"name": "Chocolate Chip Cookies",
"ingredients": [
"All-purpose flour",
"Butter, softened",
"Brown sugar",
"White sugar",
"Eggs",
"Vanilla extract",
"Baking soda",
"Salt",
"Chocolate chips"
],
"instructions": [
"Preheat the oven to 350°F (175°C).",
"In a bowl, cream together softened butter, brown sugar, and white sugar.",
"Beat in eggs one at a time, then stir in vanilla extract.",
"Combine flour, baking soda, and salt. Gradually add to the wet ingredients.",
"Fold in chocolate chips.",
"Drop rounded tablespoons of dough onto ungreased baking sheets.",
"Bake for 10-12 minutes or until edges are golden brown.",
"Allow cookies to cool on the baking sheet for a few minutes before transferring to a wire rack."
],
"prepTimeMinutes": 15,
"cookTimeMinutes": 10,
"servings": 24,
"difficulty": "Easy",
"cuisine": "American",
"caloriesPerServing": 150,
"tags": [
"Cookies",
"Dessert",
"Baking"
],
"userId": 34,
"image": "https://cdn.dummyjson.com/recipe-images/3.webp",
"rating": 4.9,
"reviewCount": 13,
"mealType": [
"Snack",
"Dessert"
]
},
{
"id": 4,
"name": "Chicken Alfredo Pasta",
"ingredients": [
"Fettuccine pasta",
"Chicken breast, sliced",
"Heavy cream",
"Parmesan cheese, grated",
"Garlic, minced",
"Butter",
"Salt and pepper to taste",
"Fresh parsley for garnish"
],
"instructions": [
"Cook fettuccine pasta according to package instructions.",
"In a pan, sauté sliced chicken in butter until fully cooked.",
"Add minced garlic and cook until fragrant.",
"Pour in heavy cream and grated Parmesan cheese. Stir until the cheese is melted.",
"Season with salt and pepper to taste.",
"Combine the Alfredo sauce with cooked pasta.",
"Garnish with fresh parsley before serving."
],
"prepTimeMinutes": 15,
"cookTimeMinutes": 20,
"servings": 4,
"difficulty": "Medium",
"cuisine": "Italian",
"caloriesPerServing": 500,
"tags": [
"Pasta",
"Chicken"
],
"userId": 136,
"image": "https://cdn.dummyjson.com/recipe-images/4.webp",
"rating": 4.9,
"reviewCount": 82,
"mealType": [
"Lunch",
"Dinner"
]
},
{
"id": 5,
"name": "Mango Salsa Chicken",
"ingredients": [
"Chicken thighs",
"Mango, diced",
"Red onion, finely chopped",
"Cilantro, chopped",
"Lime juice",
"Jalapeño, minced",
"Salt and pepper to taste",
"Cooked rice for serving"
],
"instructions": [
"Season chicken thighs with salt and pepper.",
"Grill or bake chicken until fully cooked.",
"In a bowl, combine diced mango, chopped red onion, cilantro, minced jalapeño, and lime juice.",
"Dice the cooked chicken and mix it with the mango salsa.",
"Serve over cooked rice."
],
"prepTimeMinutes": 15,
"cookTimeMinutes": 25,
"servings": 3,
"difficulty": "Easy",
"cuisine": "Mexican",
"caloriesPerServing": 380,
"tags": [
"Chicken",
"Salsa"
],
"userId": 26,
"image": "https://cdn.dummyjson.com/recipe-images/5.webp",
"rating": 4.9,
"reviewCount": 63,
"mealType": [
"Dinner"
]
},
{
"id": 6,
"name": "Quinoa Salad with Avocado",
"ingredients": [
"Quinoa, cooked",
"Avocado, diced",
"Cherry tomatoes, halved",
"Cucumber, diced",
"Red bell pepper, diced",
"Feta cheese, crumbled",
"Lemon vinaigrette dressing",
"Salt and pepper to taste"
],
"instructions": [
"In a large bowl, combine cooked quinoa, diced avocado, halved cherry tomatoes, diced cucumber, diced red bell pepper, and crumbled feta cheese.",
"Drizzle with lemon vinaigrette dressing and toss to combine.",
"Season with salt and pepper to taste.",
"Chill in the refrigerator before serving."
],
"prepTimeMinutes": 20,
"cookTimeMinutes": 15,
"servings": 4,
"difficulty": "Easy",
"cuisine": "Mediterranean",
"caloriesPerServing": 280,
"tags": [
"Salad",
"Quinoa"
],
"userId": 197,
"image": "https://cdn.dummyjson.com/recipe-images/6.webp",
"rating": 4.4,
"reviewCount": 59,
"mealType": [
"Lunch",
"Side Dish"
]
},
{
"id": 7,
"name": "Tomato Basil Bruschetta",
"ingredients": [
"Baguette, sliced",
"Tomatoes, diced",
"Fresh basil, chopped",
"Garlic cloves, minced",
"Balsamic glaze",
"Olive oil",
"Salt and pepper to taste"
],
"instructions": [
"Preheat the oven to 375°F (190°C).",
"Place baguette slices on a baking sheet and toast in the oven until golden brown.",
"In a bowl, combine diced tomatoes, chopped fresh basil, minced garlic, and a drizzle of olive oil.",
"Season with salt and pepper to taste.",
"Top each toasted baguette slice with the tomato-basil mixture.",
"Drizzle with balsamic glaze before serving."
],
"prepTimeMinutes": 15,
"cookTimeMinutes": 10,
"servings": 6,
"difficulty": "Easy",
"cuisine": "Italian",
"caloriesPerServing": 120,
"tags": [
"Bruschetta",
"Italian"
],
"userId": 137,
"image": "https://cdn.dummyjson.com/recipe-images/7.webp",
"rating": 4.7,
"reviewCount": 95,
"mealType": [
"Appetizer"
]
},
{
"id": 8,
"name": "Beef and Broccoli Stir-Fry",
"ingredients": [
"Beef sirloin, thinly sliced",
"Broccoli florets",
"Soy sauce",
"Oyster sauce",
"Sesame oil",
"Garlic, minced",
"Ginger, minced",
"Cornstarch",
"Cooked white rice for serving"
],
"instructions": [
"In a bowl, mix soy sauce, oyster sauce, sesame oil, and cornstarch to create the sauce.",
"In a wok, stir-fry thinly sliced beef until browned. Remove from the wok.",
"Stir-fry broccoli florets, minced garlic, and minced ginger in the same wok.",
"Add the cooked beef back to the wok and pour the sauce over the mixture.",
"Stir until everything is coated and heated through.",
"Serve over cooked white rice."
],
"prepTimeMinutes": 20,
"cookTimeMinutes": 15,
"servings": 4,
"difficulty": "Medium",
"cuisine": "Asian",
"caloriesPerServing": 380,
"tags": [
"Beef",
"Stir-fry",
"Asian"
],
"userId": 18,
"image": "https://cdn.dummyjson.com/recipe-images/8.webp",
"rating": 4.7,
"reviewCount": 58,
"mealType": [
"Dinner"
]
},
{
"id": 9,
"name": "Caprese Salad",
"ingredients": [
"Tomatoes, sliced",
"Fresh mozzarella cheese, sliced",
"Fresh basil leaves",
"Balsamic glaze",
"Extra virgin olive oil",
"Salt and pepper to taste"
],
"instructions": [
"Arrange alternating slices of tomatoes and fresh mozzarella on a serving platter.",
"Tuck fresh basil leaves between the slices.",
"Drizzle with balsamic glaze and extra virgin olive oil.",
"Season with salt and pepper to taste.",
"Serve immediately as a refreshing salad."
],
"prepTimeMinutes": 10,
"cookTimeMinutes": 0,
"servings": 2,
"difficulty": "Easy",
"cuisine": "Italian",
"caloriesPerServing": 200,
"tags": [
"Salad",
"Caprese"
],
"userId": 128,
"image": "https://cdn.dummyjson.com/recipe-images/9.webp",
"rating": 4.6,
"reviewCount": 82,
"mealType": [
"Lunch"
]
}
],
"total": 50,
"skip": 0,
"limit": 9
}
HTML et CSS
Le HTML et le CSS sont fournis, vous allez devoir les transformer en composants React et pouvoir passer d'une vue "Liste des recettes" à une vue détaillée d'une recette.
Le CSS :
:root {
--primary: #e67e22;
--dark: #2d3436;
--light-gray: #f9f9f9;
--border: #eee;
--text: #636e72;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background-color: #f0f2f5;
color: var(--dark);
margin: 0;
line-height: 1.6;
}
.container {
max-width: 1100px;
margin: 0 auto;
padding: 40px 20px;
}
/* --- LISTE DES RECETTES --- */
.header {
text-align: center;
margin-bottom: 50px;
}
.recipe-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 30px;
}
.recipe-card {
background: white;
border-radius: 15px;
overflow: hidden;
box-shadow: 0 4px 15px rgba(0,0,0,0.1);
transition: transform 0.3s ease;
}
.recipe-card:hover { transform: translateY(-5px); }
.card-image { position: relative; height: 200px; }
.card-image img { width: 100%; height: 100%; object-fit: cover; }
.badge {
position: absolute;
top: 10px;
right: 10px;
background: var(--primary);
color: white;
padding: 5px 12px;
border-radius: 20px;
font-size: 0.8rem;
}
.card-content { padding: 20px; }
.card-content h3 { margin: 0 0 10px 0; font-size: 1.25rem; }
.card-meta {
display: flex;
justify-content: space-between;
font-size: 0.9rem;
color: var(--text);
margin-bottom: 20px;
}
.card-footer {
display: flex;
justify-content: space-between;
align-items: center;
border-top: 1px solid var(--border);
padding-top: 15px;
}
.difficulty { font-weight: bold; text-transform: uppercase; font-size: 0.75rem; }
.easy { color: #27ae60; }
.medium { color: #f39c12; }
.btn-details {
background: var(--dark);
color: white;
border: none;
padding: 8px 16px;
border-radius: 8px;
cursor: pointer;
text-decoration: none;
font-size: 0.9rem;
}
/* --- DÉTAILS DE LA RECETTE --- */
.btn-back {
background: var(--dark);
color: white;
border: none;
padding: 10px 20px;
border-radius: 8px;
cursor: pointer;
margin-bottom: 30px;
display: inline-block;
}
.detail-header {
display: flex;
gap: 30px;
align-items: center;
margin-bottom: 40px;
}
.detail-hero {
width: 400px;
height: 300px;
border-radius: 20px;
object-fit: cover;
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
}
.detail-title-block h1 {
font-size: 2.5rem;
margin: 0 0 15px 0;
}
.tags {
display: flex;
gap: 10px;
}
.tag {
background: #dfe6e9;
padding: 6px 15px;
border-radius: 20px;
font-size: 0.9rem;
color: var(--dark);
}
.detail-grid {
display: grid;
grid-template-columns: 2fr 1fr;
gap: 40px;
}
.detail-main {
background: white;
padding: 30px;
border-radius: 20px;
box-shadow: 0 4px 15px rgba(0,0,0,0.05);
}
.info-card, .ingredients-card {
background: white;
padding: 25px;
border-radius: 15px;
margin-bottom: 20px;
box-shadow: 0 4px 15px rgba(0,0,0,0.05);
}
.instructions-list { padding-left: 20px; }
.instructions-list li { margin-bottom: 20px; padding-left: 10px; }
.ingredients-list { list-style: none; padding: 0; }
.ingredients-list li {
padding: 12px 0;
border-bottom: 1px solid var(--border);
display: flex;
align-items: center;
}
.ingredients-list li::before {
content: "•";
color: var(--primary);
font-weight: bold;
margin-right: 10px;
}
/* Responsive */
@media (max-width: 850px) {
.detail-grid { grid-template-columns: 1fr; }
.detail-header { flex-direction: column; text-align: center; }
.detail-hero { width: 100%; height: auto; }
.tags { justify-content: center; }
}
HTML pour la page de liste des recettes :
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Recettes de Cuisine - Liste</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<header class="header">
<h1>Nos Recettes Gourmandes</h1>
<p>Découvrez des plats savoureux pour toutes les occasions.</p>
</header>
<main class="recipe-grid">
<article class="recipe-card">
<div class="card-image">
<img src="https://cdn.dummyjson.com/recipe-images/1.webp" alt="Classic Margherita Pizza">
<span class="badge">Italian</span>
</div>
<div class="card-content">
<h3>Classic Margherita Pizza</h3>
<div class="card-meta">
<span>⏱ 35 min</span>
<span>🔥 300 kcal</span>
</div>
<div class="card-footer">
<span class="difficulty easy">Easy</span>
<button class="btn-details">Voir la recette</button>
</div>
</div>
</article>
<article class="recipe-card">
<div class="card-image">
<img src="https://cdn.dummyjson.com/recipe-images/2.webp" alt="Vegetarian Stir-Fry">
<span class="badge">Asian</span>
</div>
<div class="card-content">
<h3>Vegetarian Stir-Fry</h3>
<div class="card-meta">
<span>⏱ 35 min</span>
<span>🔥 250 kcal</span>
</div>
<div class="card-footer">
<span class="difficulty medium">Medium</span>
<button class="btn-details">Voir la recette</button>
</div>
</div>
</article>
<article class="recipe-card">
<div class="card-image">
<img src="https://cdn.dummyjson.com/recipe-images/3.webp" alt="Chocolate Chip Cookies">
<span class="badge">American</span>
</div>
<div class="card-content">
<h3>Chocolate Chip Cookies</h3>
<div class="card-meta">
<span>⏱ 25 min</span>
<span>🔥 150 kcal</span>
</div>
<div class="card-footer">
<span class="difficulty easy">Easy</span>
<button class="btn-details">Voir la recette</button>
</div>
</div>
</article>
</main>
</div>
</body>
</html>
HTML de la page de détails d'une recette :
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Recette - Détails</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<button class="btn-back">← Retour à la liste</button>
<section class="recipe-detail">
<div class="detail-header">
<img src="https://cdn.dummyjson.com/recipe-images/1.webp" alt="Classic Margherita Pizza" class="detail-hero">
<div class="detail-title-block">
<h1>Classic Margherita Pizza</h1>
<div class="tags">
<span class="tag">Pizza</span>
<span class="tag">Italian</span>
<span class="tag">Dinner</span>
</div>
</div>
</div>
<div class="detail-grid">
<div class="detail-main">
<section>
<h2>Instructions</h2>
<ol class="instructions-list">
<li>Preheat the oven to 475°F (245°C).</li>
<li>Roll out the pizza dough and spread tomato sauce evenly.</li>
<li>Top with slices of fresh mozzarella and fresh basil leaves.</li>
<li>Drizzle with olive oil and season with salt and pepper.</li>
<li>Bake in the preheated oven for 12-15 minutes or until the crust is golden brown.</li>
<li>Slice and serve hot.</li>
</ol>
</section>
</div>
<aside class="detail-sidebar">
<div class="info-card">
<h3>Informations</h3>
<p><strong>Difficulté :</strong> Easy</p>
<p><strong>Portions :</strong> 4 personnes</p>
<p><strong>Calories :</strong> 300 kcal / pers.</p>
<p><strong>Note :</strong> 4.6 ⭐ (98 avis)</p>
</div>
<div class="ingredients-card">
<h3>Ingrédients</h3>
<ul class="ingredients-list">
<li>Pizza dough</li>
<li>Tomato sauce</li>
<li>Fresh mozzarella cheese</li>
<li>Fresh basil leaves</li>
<li>Olive oil</li>
<li>Salt and pepper to taste</li>
</ul>
</div>
</aside>
</div>
</section>
</div>
</body>
</html>
05 February 2026