DEV Community

Cover image for Building a Quiz Application with React
Abhishek Gurjar
Abhishek Gurjar

Posted on

Building a Quiz Application with React

Introduction

In this tutorial, we will walk you through building a fun and interactive Quiz Website using React. This project is a great way for beginners to practice handling user input, managing state, and rendering dynamic content in React.

Project Overview

The Quiz Website allows users to answer multiple-choice questions and get instant feedback on their selections. At the end of the quiz, users are shown their scores along with the correct answers.

Features

  • Interactive Quiz: Users can answer questions and see their scores.
  • Real-Time Feedback: Immediate indication of whether the selected answer is correct or not.
  • Score Calculation: Keeps track of the score throughout the quiz.
  • Dynamic Content: Questions and options are rendered dynamically from a predefined list.

Technologies Used

  • React: For building the user interface and managing component states.
  • CSS: For styling the application.
  • JavaScript: For handling logic and quiz functionality.

Project Structure

The project is structured as follows:

├── public
├── src
│   ├── components
│   │   ├── Quiz.jsx
│   │   ├── Question.jsx
│   ├── App.jsx
│   ├── App.css
│   ├── index.js
│   └── index.css
├── package.json
└── README.md
Enter fullscreen mode Exit fullscreen mode

Key Components

  • Quiz.jsx: Handles the quiz logic and score calculation.
  • Question.jsx: Displays individual questions and handles user input.
  • App.jsx: Manages the layout and renders the Quiz component.

Code Explanation

Quiz Component

The Quiz component is responsible for rendering the questions, calculating the score, and handling quiz completion.

import  { useEffect, useState } from "react";
import Result from "./Result";
import Question from "./Question";
const data = [
  {
    question: "What is the capital of France?",
    options: ["Paris", "Berlin", "Madrid", "Rome"],
    answer: "Paris",
  },
  {
    question: "What is the capital of Germany?",
    options: ["Berlin", "Munich", "Frankfurt", "Hamburg"],
    answer: "Berlin",
  },
  {
    question: "What is the capital of Spain?",
    options: ["Madrid", "Barcelona", "Seville", "Valencia"],
    answer: "Madrid",
  },
  {
    question: "What is the capital of Italy?",
    options: ["Rome", "Milan", "Naples", "Turin"],
    answer: "Rome",
  },
  {
    question: "What is the capital of the United Kingdom?",
    options: ["London", "Manchester", "Liverpool", "Birmingham"],
    answer: "London",
  },
  {
    question: "What is the capital of Canada?",
    options: ["Ottawa", "Toronto", "Vancouver", "Montreal"],
    answer: "Ottawa",
  },
  {
    question: "What is the capital of Australia?",
    options: ["Canberra", "Sydney", "Melbourne", "Brisbane"],
    answer: "Canberra",
  },
  {
    question: "What is the capital of Japan?",
    options: ["Tokyo", "Osaka", "Kyoto", "Nagoya"],
    answer: "Tokyo",
  },
  {
    question: "What is the capital of China?",
    options: ["Beijing", "Shanghai", "Guangzhou", "Shenzhen"],
    answer: "Beijing",
  },
  {
    question: "What is the capital of Russia?",
    options: ["Moscow", "Saint Petersburg", "Novosibirsk", "Yekaterinburg"],
    answer: "Moscow",
  },
  {
    question: "What is the capital of India?",
    options: ["New Delhi", "Mumbai", "Bangalore", "Chennai"],
    answer: "New Delhi",
  },
  {
    question: "What is the capital of Brazil?",
    options: ["Brasilia", "Rio de Janeiro", "Sao Paulo", "Salvador"],
    answer: "Brasilia",
  },
  {
    question: "What is the capital of Mexico?",
    options: ["Mexico City", "Guadalajara", "Monterrey", "Tijuana"],
    answer: "Mexico City",
  },
  {
    question: "What is the capital of South Africa?",
    options: ["Pretoria", "Johannesburg", "Cape Town", "Durban"],
    answer: "Pretoria",
  },
  {
    question: "What is the capital of Egypt?",
    options: ["Cairo", "Alexandria", "Giza", "Luxor"],
    answer: "Cairo",
  },
  {
    question: "What is the capital of Turkey?",
    options: ["Ankara", "Istanbul", "Izmir", "Antalya"],
    answer: "Ankara",
  },
  {
    question: "What is the capital of Argentina?",
    options: ["Buenos Aires", "Cordoba", "Rosario", "Mendoza"],
    answer: "Buenos Aires",
  },
  {
    question: "What is the capital of Nigeria?",
    options: ["Abuja", "Lagos", "Kano", "Ibadan"],
    answer: "Abuja",
  },
  {
    question: "What is the capital of Saudi Arabia?",
    options: ["Riyadh", "Jeddah", "Mecca", "Medina"],
    answer: "Riyadh",
  },
  {
    question: "What is the capital of Indonesia?",
    options: ["Jakarta", "Surabaya", "Bandung", "Medan"],
    answer: "Jakarta",
  },
  {
    question: "What is the capital of Thailand?",
    options: ["Bangkok", "Chiang Mai", "Phuket", "Pattaya"],
    answer: "Bangkok",
  },
  {
    question: "What is the capital of Malaysia?",
    options: ["Kuala Lumpur", "George Town", "Johor Bahru", "Malacca"],
    answer: "Kuala Lumpur",
  },
  {
    question: "What is the capital of the Philippines?",
    options: ["Manila", "Cebu City", "Davao City", "Quezon City"],
    answer: "Manila",
  },
  {
    question: "What is the capital of Vietnam?",
    options: ["Hanoi", "Ho Chi Minh City", "Da Nang", "Hai Phong"],
    answer: "Hanoi",
  },
  {
    question: "What is the capital of South Korea?",
    options: ["Seoul", "Busan", "Incheon", "Daegu"],
    answer: "Seoul",
  },
];
const Quiz = () => {
  const [currentQuestion, setCurrentQuestion] = useState(0);
  const [score, setScore] = useState(0);
  const [showResult, setShowResult] = useState(false);
  const [timer, setTimer] = useState(30);
  const [showNextButton, setShowNextButton] = useState(true);

  useEffect(() => {
    if (timer === 0) {
      handleNext();
    }
    const timerId = setTimeout(() => setTimer(timer - 1), 1000);
    return () => clearTimeout(timerId);
  }, [timer]);

  const handleAnswer = (selectedOption) => {
    if (selectedOption === data[currentQuestion].answer) {
      setScore(score + 1);
    }
    setShowNextButton(true); // Show the next button after answering
  };

  const handleNext = () => {
    const nextQuestion = currentQuestion + 1;
    if (nextQuestion < data.length) {
      setCurrentQuestion(nextQuestion);
    } else {
      setShowResult(true);
    }
    setShowNextButton(true); // Hide the next button after moving to the next question
    setTimer(30);
  };

  if (showResult) {
    return <Result score={score} totalQuestion={data.length} />;
  }

  return (
    <div className="quiz">
<div className="countandTime">
<div className="questionNumber">
       Question :  {currentQuestion + 1} <b>/</b> {data.length}
      </div>
      <div className="timer">Time left : {timer} seconds</div>
</div>
      <Question
        question={data[currentQuestion].question}
        options={data[currentQuestion].options}
        onAnswer={handleAnswer}
        onNext={handleNext}
        showNextButton={showNextButton}
      />
    </div>
  );
};

export default Quiz;

Enter fullscreen mode Exit fullscreen mode

The Quiz component manages the current question index and score. It also tracks when the quiz is finished, displaying the final score once all questions are answered.

Question Component

The Question component handles the display of each question and allows the user to select an answer.

const Question = ({ question, options, onAnswer, onNext, showNextButton }) => {
  return (
    <div className="question">
      <h2>{question}</h2>
      {options.map((option, index) => (
        <button className="option" key={index} onClick={() => onAnswer(option)}>
          {option}
        </button>
      ))}
      {showNextButton && <button className="next" onClick={onNext}>Next </button>}
    </div>
  );
};

export default Question;

Enter fullscreen mode Exit fullscreen mode

This component takes the data prop, which includes the question and its options, and renders it dynamically. The handleAnswer function processes the selected option.

App Component

The App component manages the layout and renders the Quiz component.

import Quiz from "./components/Quiz";
import "./App.css";
import logo from "./assets/images/quizlogo.png";
const App = () => {
  return (
    <div className="app">
      <img className="logo" src={logo} alt="logo" />
      <Quiz />
      <p className="footer">Made with ❤️ by Abhishek Gurjar</p>
    </div>
  );
};

export default App;

Enter fullscreen mode Exit fullscreen mode

This component structures the page with a header and footer, and the Quiz component is rendered in the center.

Result Component

The Result component is responsible for showing the user's quiz score after they submit their answers. It calculates the score by comparing the user's responses with the correct answers and provides feedback on how many questions were answered correctly.

const Result = ({ score, totalQuestion }) => {
  return (
    <div className='result'>
      <h2>Quiz Complete</h2>
      <p>Your score is {score} out of {totalQuestion}</p>
    </div>
  );
}

export default Result;

Enter fullscreen mode Exit fullscreen mode

In this component, the score and total number of questions are passed as props. Based on the score, the component displays a message to the user, either praising them for getting all the answers correct or encouraging them to keep practicing. This dynamic feedback helps users understand their performance.

CSS Styling

The CSS ensures a clean and simple layout for the quiz. It styles the quiz components and provides user-friendly visuals.

* {
  box-sizing: border-box;
}
body {
  background-color: #cce2c2;
  color: black;
  margin: 0;
  padding: 0;
  font-family: sans-serif;
}
.app {
  width: 100%;

  display: flex;
  align-items: center;
  justify-content: flex-start;
  flex-direction: column;
}
.app img {
  margin: 50px;
}

/* Quiz */
.quiz {
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 60%;
  margin: 0 auto;
}
.countandTime {
  display: flex;
  align-items: center;
  gap: 300px;
}
.questionNumber {
  font-size: 20px;
  background-color: #fec33d;
  padding: 10px;
  border-radius: 10px;
  font-weight: bold;
}
.timer {
  font-size: 18px;
  background-color: #44b845;
  color: white;
  padding: 10px;
  border-radius: 10px;
  font-weight: bold;
}

/* Question */

.question {
  margin-top: 20px;
}
.question h2 {
  background-color: #eaf0e7;
  width: 690px;
  padding: 30px;
  border-radius: 10px;
}
.question .option {
  display: flex;
  margin-block: 20px;
  flex-direction: column;
  align-items: flex-start;
  background-color: #eaf0e7;
  padding: 20px;
  border-radius: 10px;
  font-size: 18px;
  width: 690px;
}

.question .next {
  font-size: 25px;
  color: white;
  background-color: #35bd3a;
  border: none;
  padding: 10px;
  width: 100px;
  border-radius: 10px;

  margin-left: 590px;
}

/* Result */

.result {
  border-radius: 19px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  width: 500px;
  height: 300px;
  margin-top: 140px;
  background-color: #35bd3a;
  color: white;
}
.result h2{
  font-size: 40px;
}
.result p{
  font-size: 25px;
}

.footer {
  margin: 40px;
}
Enter fullscreen mode Exit fullscreen mode

The styling ensures that the layout is centered and provides hover effects on the quiz options, making it more interactive.

Installation and Usage

To get started with this project, clone the repository and install the dependencies:

git clone https://github.com/abhishekgurjar-in/quiz-website.git
cd quiz-website
npm install
npm start
Enter fullscreen mode Exit fullscreen mode

This will start the development server, and the application will be running at http://localhost:3000.

Live Demo

Check out the live demo of the Quiz Website here.

Conclusion

This Quiz Website is an excellent project for beginners looking to enhance their React skills. It provides an engaging way to practice managing state, rendering dynamic content, and handling user input.

Credits

  • Inspiration: The project is inspired by the classic quiz games, combining fun and learning.

Author

Abhishek Gurjar is a web developer passionate about building interactive and engaging web applications. You can follow his work on GitHub.

Top comments (2)

Collapse
 
marciobugad0 profile image
Marcio Souza

Thats pretty nice!

Collapse
 
annsrutto profile image
Anns Rutto

Nice project. Kindly improve on the mobile view for different devices.