Skip to main content

🎯 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/link pour la navigation, pas next/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.tsx comme 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)
  • 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 useState pour gĂ©rer l'Ă©tat local
  • Pour le feedback visuel : changez la couleur du bouton avec color="success" ou color="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 useRouter pour la navigation programmatique
  • CrĂ©er des composants rĂ©utilisables

✅ Tñches​

3.1 - Détecter la fin du quiz

  • VĂ©rifier si currentQuestionIndex a 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 useRouter de next/navigation pour 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() ou window.location.reload()
  • Pour rĂ©initialiser l'Ă©tat : crĂ©er une fonction resetQuiz() qui remet tout Ă  zĂ©ro
  • Utilisez Accordion de 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 GET qui 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, utiliser useEffect pour 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.ts avec une fonction getQuestions()
  • 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...catch pour 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/react et jest
  • É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 useEffect pour 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, isFinished
    • selectAnswer(), 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​

  1. Créer un compte Vercel (gratuit)
  2. Connecter votre repository GitHub
  3. Déployer en un clic
  4. Partager le lien avec vos collĂšgues !

Guide : Documentation Vercel


💡 Conseils GĂ©nĂ©raux​

🎯 Approche recommandĂ©e​

  1. Suivez l'ordre des étapes : Chaque étape s'appuie sur la précédente
  2. Testez réguliÚrement : Vérifiez que tout fonctionne avant de passer à l'étape suivante
  3. Lisez la documentation : Next.js et Material UI ont d'excellentes docs
  4. Consultez les indices : Ne restez pas bloqué, utilisez les <details> !
  5. 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...catch avec async/await
  • GĂ©rez les Ă©tats loading et error avec 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 :

  1. Accédez au dossier quiz-capitales-starter
  2. Suivez les instructions d'installation dans le README du starter
  3. Suivez les étapes du MECA une par une
  4. Présentez votre solution finale

Bon courage et bon apprentissage ! đŸ’Ș