đŻ MECA - Quiz des Capitales EuropĂ©ennes
Introductionâ
Bienvenue dans ce MECA Next.js ! Vous allez créer une application de quiz interactive pour tester vos connaissances sur les capitales européennes.
Prérequis :
- â Formation React complĂ©tĂ©e (composants, hooks, JSX)
- â Notions de TypeScript
- đ NextJS-Fundamentals.md (lecture obligatoire)
đĄ Important : Ce MECA suppose que vous avez lu et compris le cours NextJS-Fundamentals.md.
đ Installation rapideâ
Un projet starter complet est fourni dans le dossier quiz-capitales-starter.
cd quiz-capitales-starter
npm install
npm run dev
Le projet est déjà configuré avec Next.js 15, React 19, Material UI v6 et les tests. Vous pouvez commencer directement l'exercice !
đ Objectifs pĂ©dagogiquesâ
Ă la fin de ce MECA, vous serez capable de :
â CrĂ©er une application Next.js 15 complĂšte avec App Router â Distinguer et utiliser Server Components vs Client Components â GĂ©rer l'Ă©tat local avec useState et useEffect â CrĂ©er des API Routes et Server Actions â IntĂ©grer des APIs tierces (Open Trivia DB, OpenDataSoft) â Optimiser les performances (cache, Server Actions) â Tester vos composants React â DĂ©ployer sur Vercel
đ Concepts techniques couvertsâ
- App Router : Navigation moderne Next.js 15
- Server Components : Rendu cÎté serveur pour les performances
- Client Components : Interactivité cÎté client
- API Routes : Création d'endpoints REST
- Server Actions : Actions serveur pour mutations
- State Management : useState, useEffect, custom hooks
- Material UI : BibliothÚque de composants React (non imposé)
- Tests : Testing Library pour composants React
đ Parcours d'apprentissage progressifâ
Ce MECA est structuré en 5 étapes progressives. Chaque étape s'appuie sur la précédente. Prenez le temps de bien comprendre chaque concept avant de passer à l'étape suivante.
Ătape 1 : Setup et Page d'Accueilâ
đŻ Objectifâ
Créer une application Next.js 15 fonctionnelle avec une page d'accueil attrayante.
đ Ce que vous allez apprendreâ
- Initialiser un projet Next.js 15 avec TypeScript
- Configurer Material UI v6
- Créer un Server Component (page.tsx)
- Utiliser le systĂšme de routing Next.js (App Router)
â TĂąchesâ
1.1 - Initialiser le projet
- Suivre les instructions du dossier quiz-capitales-starter pour démarrer
- Les dépendances (Next.js 15, Material UI, TypeScript) sont déjà installées
- Vérifier que le serveur de développement démarre correctement avec
npm run dev
1.2 - Créer la page d'accueil (app/page.tsx)
- Créer un Server Component avec :
- Un titre accrocheur "Quiz des Capitales Européennes"
- Une description du quiz
- Un bouton "Commencer le Quiz" stylisé avec Material UI
- Utiliser les composants Material UI :
Box,Typography,Button
1.3 - Ajouter la navigation
- Utiliser le composant
<Link>de Next.js pour naviguer vers/quiz - Comprendre la différence entre
<Link>et<a>
1.4 - Styling
- Ajouter une image de fond depuis
/public - Centrer le contenu avec Flexbox (Material UI
Box) - Rendre la page responsive
đ Indices
- Le Server Component par défaut n'a PAS besoin de
'use client' - Material UI nécessite un ThemeProvider dans
layout.tsx - Utilisez
next/linkpour la navigation, pasnext/router
đ Concepts clĂ©s :
- Server Component : Rendu cÎté serveur, pas d'interactivité, performances optimales
- App Router : Nouveau systÚme de routing de Next.js 15 basé sur les dossiers
Ătape 2 : Page Quiz avec DonnĂ©es Statiquesâ
đŻ Objectifâ
Afficher des questions de quiz avec des données en dur et gérer l'état local.
đ Ce que vous allez apprendreâ
- Créer un Client Component avec
'use client' - Gérer l'état avec
useState - Afficher dynamiquement des données
- Valider les réponses utilisateur
â TĂąchesâ
2.1 - Créer la route /quiz
- Créer le dossier
app/quiz/ - Créer
app/quiz/page.tsxcomme Client Component ('use client'en premiĂšre ligne) - Importer les questions depuis
QUESTIONS.json(fourni)
2.2 - Afficher une question
- Créer un état pour :
- La question actuelle (
currentQuestionIndex) - Le score (
score) - La réponse sélectionnée (
selectedAnswer)
- La question actuelle (
- Afficher la question et les choix de réponses sous forme de boutons Material UI
2.3 - Valider la réponse
- Au clic sur un bouton, vérifier si la réponse est correcte
- Afficher un feedback visuel (vert si correct, rouge si incorrect)
- Incrémenter le score si la réponse est correcte
- Afficher la bonne réponse en cas d'erreur
2.4 - Navigation entre questions
- Ajouter un bouton "Question Suivante"
- Passer à la question suivante et réinitialiser la sélection
- Désactiver le bouton tant qu'aucune réponse n'est sélectionnée
đ Indices
- Utilisez
useStatepour gérer l'état local - Pour le feedback visuel : changez la couleur du bouton avec
color="success"oucolor="error" - Structure de données suggérée pour une question :
{
question: "Quelle est la capitale de la France ?",
choices: ["Paris", "Londres", "Berlin", "Madrid"],
correctAnswer: "Paris"
}
đ Concepts clĂ©s :
- Client Component : Permet l'interactivité (useState, useEffect, événements)
- useState : Hook pour gérer l'état local d'un composant
- Rendu conditionnel : Afficher différents contenus selon l'état
Ătape 3 : Page de RĂ©sultats et Recommencerâ
đŻ Objectifâ
Afficher le score final et permettre de recommencer le quiz.
đ Ce que vous allez apprendreâ
- Gérer la fin d'un flux utilisateur
- Utiliser
useRouterpour la navigation programmatique - Créer des composants réutilisables
â TĂąchesâ
3.1 - Détecter la fin du quiz
- Vérifier si
currentQuestionIndexa atteint la derniÚre question - Afficher un écran de résultats au lieu d'une question
3.2 - Créer l'écran de résultats
- Afficher le score final : "Vous avez obtenu X/10 !"
- Afficher un message personnalisé selon le score :
- < 5 : "Continuez Ă apprendre !"
- 5-7 : "Pas mal ! Encore un effort."
- 8-10 : "Excellent ! Vous maĂźtrisez bien !"
- Styliser avec Material UI (
Card,Typography)
3.3 - Bouton "Recommencer"
- Ajouter un bouton pour recommencer le quiz
- Utiliser
useRouterdenext/navigationpour recharger la page - Alternative : réinitialiser tous les états manuellement
3.4 - Bonus : Afficher un récapitulatif
- Pour chaque question, afficher si la réponse était correcte ou non
- Utiliser un accordéon Material UI pour ne pas surcharger l'écran
đ Indices
- Pour recharger la page :
router.refresh()ouwindow.location.reload() - Pour réinitialiser l'état : créer une fonction
resetQuiz()qui remet tout à zéro - Utilisez
Accordionde Material UI pour le récapitulatif
đ Concepts clĂ©s :
- useRouter : Hook pour la navigation programmatique Next.js
- Logique conditionnelle : Afficher différents composants selon l'état
- Composants réutilisables : Extraire la logique commune
Ătape 4 : API Routes et Server Actionsâ
đŻ Objectifâ
Créer une API pour servir les questions et comprendre les Server Actions.
đ Ce que vous allez apprendreâ
- Créer une API Route Next.js
- Faire un fetch depuis un Client Component
- Créer et utiliser des Server Actions
- Gérer les erreurs réseau
â TĂąchesâ
4.1 - Créer une API Route
- Créer
app/api/questions/route.ts - Exporter une fonction
GETqui retourne les questions en JSON - Tester l'endpoint avec le navigateur :
http://localhost:3000/api/questions
4.2 - Fetch depuis le Client Component
- Dans
app/quiz/page.tsx, utiliseruseEffectpour fetch les questions au montage - Gérer les états de chargement (
loading) et d'erreur (error) - Afficher un spinner Material UI pendant le chargement
4.3 - Créer une Server Action (optionnel mais recommandé)
- Créer
app/actions/quiz.tsavec une fonctiongetQuestions() - Marquer la fonction avec
'use server' - Remplacer le fetch par un appel Ă cette Server Action
- Comprendre les avantages (pas d'exposition d'endpoint, plus sécurisé)
4.4 - Gestion d'erreurs
- Utiliser
try...catchpour gérer les erreurs - Afficher un message d'erreur convivial si le fetch échoue
- Ajouter un bouton "Réessayer"
đ Indices
-
Structure d'une API Route :
export async function GET() {
return Response.json({ questions: [...] })
} -
Fetch dans useEffect avec async/await :
useEffect(() => {
const fetchQuestions = async () => {
try {
const res = await fetch("/api/questions");
if (!res.ok) throw new Error("Erreur de chargement");
const data = await res.json();
setQuestions(data.questions);
} catch (error) {
console.error(error);
}
};
fetchQuestions();
}, []); -
Server Action :
"use server";
export async function getQuestions() {
return questions;
}
đ Concepts clĂ©s :
- API Routes : Endpoints REST dans Next.js
- useEffect : Hook pour les effets de bord (fetch, timers, etc.)
- Server Actions : Fonctions serveur appelables depuis le client
- Async/await : Gestion des opérations asynchrones
Ătape 5 : Features AvancĂ©esâ
đŻ Objectifâ
Ajouter des fonctionnalités avancées pour enrichir l'expérience utilisateur.
đ Ce que vous allez apprendreâ
- Gérer des timers avec useEffect
- Intégrer des APIs tierces (Open Trivia DB, OpenDataSoft)
- Optimiser les performances avec le cache
- Créer un custom hook
â TĂąchesâ
5.1 - Tests
- Installer
@testing-library/reactetjest - Ăcrire un test pour le custom hook
useQuiz - Ăcrire un test pour un composant de question
- Vérifier que le score s'incrémente correctement
- S'assurer que les composants se comportent correctement
5.2 - Mode Défi avec Timer
- Ajouter un état
timeLeft(ex: 15 secondes par question) - Utiliser
useEffectpour décrémenter le timer chaque seconde - Afficher une barre de progression Material UI (
LinearProgress) - Passer automatiquement à la question suivante si le temps est écoulé
- Nettoyer le timer dans le cleanup de useEffect
5.3 - Intégration Open Trivia DB
- Créer une Server Action pour fetch depuis Open Trivia DB
- Transformer les données au format de votre application
- Sauvegarder les questions dans un fichier JSON pour cache
- Ajouter un bouton "Nouvelles Questions" sur la page d'accueil
5.4 - Affichage de la population
- Lors d'une bonne réponse, fetch la population depuis OpenDataSoft API
- Afficher l'info dans une carte Material UI
- GĂ©rer le cas oĂč la ville n'est pas trouvĂ©e
5.5 - Custom Hook useQuiz
- Extraire toute la logique du quiz dans un custom hook
- Le hook doit exposer :
currentQuestion,score,isFinishedselectAnswer(),nextQuestion(),resetQuiz()
- Rendre le composant page.tsx plus propre et lisible
đ Indices
-
Timer avec useEffect :
useEffect(() => {
const timer = setInterval(() => {
setTimeLeft((t) => t - 1);
}, 1000);
return () => clearInterval(timer); // Cleanup !
}, [currentQuestionIndex]); -
Open Trivia DB endpoint :
https://opentdb.com/api.php?amount=10&category=22&type=multiple -
Custom Hook :
function useQuiz(initialQuestions) {
const [score, setScore] = useState(0);
// ... toute la logique
return { score, selectAnswer, nextQuestion };
}
đ Concepts clĂ©s :
- useEffect cleanup : Nettoyer les timers/listeners pour éviter les memory leaks
- Custom Hooks : Réutiliser la logique entre composants
- API Integration : Transformer et adapter des données tierces
- Caching : Optimiser les performances en évitant les appels répétés
Ătape Finale : DĂ©ploiementâ
đŻ Objectifâ
Déployer votre application sur Vercel et la rendre accessible au monde entier.
â TĂąchesâ
- Créer un compte Vercel (gratuit)
- Connecter votre repository GitHub
- Déployer en un clic
- Partager le lien avec vos collĂšgues !
Guide : Documentation Vercel
đĄ Conseils GĂ©nĂ©rauxâ
đŻ Approche recommandĂ©eâ
- Suivez l'ordre des étapes : Chaque étape s'appuie sur la précédente
- Testez réguliÚrement : Vérifiez que tout fonctionne avant de passer à l'étape suivante
- Lisez la documentation : Next.js et Material UI ont d'excellentes docs
- Consultez les indices : Ne restez pas bloqué, utilisez les
<details>! - Expérimentez : Modifiez le code, cassez des choses, apprenez !
đ Ressources Utilesâ
Documentation officielle :
Concepts clés :
Guides pratiques :
đ€ Questions frĂ©quentesâ
Q : Quand utiliser un Server Component vs Client Component ?
Voir la réponse
- Server Component : Pas d'interactivité, fetch de données, SEO important
- Client Component : Ătat local (useState), Ă©vĂ©nements (onClick), hooks (useEffect)
// Server Component - Fetch de données
export default async function PostsList() {
const posts = await fetch("https://api.example.com/posts");
return (
<ul>
{posts.map((p) => (
<li>{p.title}</li>
))}
</ul>
);
}
// Client Component - Interactivité
'use client'
import { useState } from "react";
export default function Counter() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(count + 1)}>{count}</button>;
}
Q : Comment déboguer mon code Next.js ?
Voir la réponse
- Utilisez
console.log()cÎté serveur et client - Installez React DevTools pour inspecter les composants
- Vérifiez la console du navigateur pour les erreurs
// Débogage Server Component
export default async function Page() {
const data = await fetch("...");
console.log("Server log:", data); // Visible dans terminal
return <div>{data.title}</div>;
}
// Débogage Client Component
'use client'
export default function Component() {
console.log("Client log"); // Visible dans console navigateur
return <div>Test</div>;
}
Q : Mon composant ne se met pas Ă jour, pourquoi ?
Voir la réponse
- Vérifiez que vous appelez bien le setter de useState
- Assurez-vous que le composant est un Client Component (
'use client') - Vérifiez les dépendances de useEffect
'use client'
import { useState, useEffect } from "react";
export default function Component() {
const [data, setData] = useState([]);
useEffect(() => {
fetch("/api/data")
.then((r) => r.json())
.then(setData); // â
Utilise le setter
}, []); // â
Dépendances correctes
return <div>{data.length}</div>;
}
Q : Comment gérer les erreurs réseau ?
Voir la réponse
- Utilisez
try...catchavec async/await - Gérez les états
loadingeterroravec useState - Affichez des messages conviviaux Ă l'utilisateur
'use client'
import { useState, useEffect } from "react";
export default function DataList() {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
async function fetchData() {
try {
const res = await fetch("/api/data");
if (!res.ok) throw new Error("Erreur de chargement");
const result = await res.json();
setData(result);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
}
fetchData();
}, []);
if (loading) return <div>Chargement...</div>;
if (error) return <div>Erreur: {error}</div>;
return (
<ul>
{data.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
);
}
đš Conseils de Designâ
- CohĂ©rence : Utilisez le mĂȘme thĂšme Material UI partout
- Feedback visuel : Indiquez clairement les réponses correctes/incorrectes
- Responsive : Testez sur mobile et desktop
- Accessibilité : Utilisez des boutons et labels appropriés
- Loading states : Toujours afficher un spinner pendant les fetch
đ Structure du projetâ
Voici la structure recommandée pour ce projet :
quiz-capitales/
âââ app/
â âââ page.tsx # Page d'accueil (Server Component)
â âââ layout.tsx # Layout racine avec ThemeProvider
â âââ globals.css # Styles globaux
â â
â âââ quiz/
â â âââ page.tsx # Page du quiz (Client Component)
â â
â âââ api/
â â âââ questions/
â â âââ route.ts # API Route pour les questions
â â
â âââ actions/
â âââ quiz.ts # Server Actions
â
âââ components/ # Composants rĂ©utilisables (optionnel)
â âââ QuestionCard.tsx
â âââ ResultsScreen.tsx
â âââ Timer.tsx
â
âââ hooks/ # Custom hooks (optionnel)
â âââ useQuiz.ts
â
âââ lib/ # Utilitaires et helpers
â âââ questions.ts # Logique mĂ©tier
â
âââ public/
â âââ background.jpg # Images statiques
â
âââ data/
â âââ QUESTIONS.json # DonnĂ©es des questions
â
âââ __tests__/ # Tests (optionnel)
â âââ components/
â âââ hooks/
â
âââ package.json
âââ tsconfig.json
âââ next.config.ts
âââ README.md
đ Notes :
- La structure
components/,hooks/,lib/est optionnelle mais recommandĂ©e pour garder le code organisĂ© - Vous ĂȘtes libre d'adapter cette structure selon vos prĂ©fĂ©rences
- L'important est de bien séparer Server Components, Client Components et logique métier
đ Fichiers ComplĂ©mentairesâ
Pour vous aider dans ce MECA, consultez ces ressources :
- quiz-capitales-starter/ : Projet de démarrage avec toutes les dépendances
QUESTIONS.json: Données des questions déjà fournies dans le starter- Indices intégrés : Chaque étape contient des sections
<details>avec des indices pour vous débloquer
đ Conclusionâ
FĂ©licitations d'avoir pris le temps de lire ce MECA ! Vous ĂȘtes maintenant prĂȘt Ă crĂ©er votre application de quiz.
Rappelez-vous :
- â Prenez votre temps, c'est un apprentissage, pas une course
- â N'hĂ©sitez pas Ă expĂ©rimenter et Ă faire des erreurs
- â Consultez la documentation quand vous ĂȘtes bloquĂ©
- â Demandez de l'aide Ă vos collĂšgues (ou TO) si nĂ©cessaire
- â Amusez-vous ! đ
Prochaines étapes :
- Accédez au dossier quiz-capitales-starter
- Suivez les instructions d'installation dans le README du starter
- Suivez les étapes du MECA une par une
- Présentez votre solution finale
Bon courage et bon apprentissage ! đȘ