Single Page Application Quiz in React
Tags: react, html, css, javascript
Published: 2021-09-05 16:57:06

Hello Guys Today i am going to show you how to create a single page application quiz in react. Hope You understand everything that i will explain here.

What is Single Page Application?
An SPA (Single-page application) is a web app implementation that loads only a single web document, and then updates the body content of that single document via JavaScript when different content is to be shown.
This therefore allows users to use websites without loading whole new pages from the server, which can result in performance gains and a more dynamic experience, with some tradeoff disadvantages such as SEO, more effort required to maintain state, implement navigation, and do meaningful performance monitoring.

Lets Create our Quiz now - 

```javascript
import React, { useState } from 'react';
// import './App.css'
export default function Quiz() {
	const questions = [
		{
			questionText: 'CSS stands for -',
			answerOptions: [
				{ answerText: 'Color and style sheets', isCorrect: false },
				{ answerText: 'Cascade style sheets', isCorrect: false },
				{ answerText: 'Cascading style sheets', isCorrect: true },
				{ answerText: 'None of the above', isCorrect: false },
			],
		},
		{
			questionText: 'The property in CSS used to change the background color of an element is -',
			answerOptions: [
				{ answerText: 'bg-color', isCorrect: false },
				{ answerText: 'background-color', isCorrect: true },
				{ answerText: 'color', isCorrect: false },
				{ answerText: 'None of these', isCorrect: false },
			],
		},
		{
			questionText: ' Which of the following is the correct syntax to display the hyperlinks without any underline?',
			answerOptions: [
				{ answerText: 'a {text-decoration : none;}', isCorrect: true },
				{ answerText: 'a {text-decoration : underline;}', isCorrect: false },
				{ answerText: 'a {decoration : no-underline;}', isCorrect: false },
				{ answerText: 'None of these', isCorrect: false },
			],
		},
		{
			questionText: 'Are the negative values allowed in padding property?',
			answerOptions: [
				{ answerText: 'Yes', isCorrect: false },
				{ answerText: 'No', isCorrect: true },
				{ answerText: 'Cant say', isCorrect: false },
				{ answerText: 'Maybe', isCorrect: false },
			],
		},
		{
			questionText: 'The CSS property used to specify the transparency of an element is -',
			answerOptions: [
				{ answerText: 'filter', isCorrect: false },
				{ answerText: 'visibility', isCorrect: false },
				{ answerText: 'overlay', isCorrect: false },
				{ answerText: 'opacity', isCorrect: true },
			],
		},
		{
			questionText: 'Which of the following class in Bootstrap is used to provide a responsive fixed width container?',
			answerOptions: [
				{ answerText: '.conatiner=fixed', isCorrect: false },
				{ answerText: '.container-fluid', isCorrect: false },
				{ answerText: '.container', isCorrect: true},
				{ answerText: 'none of these', isCorrect: false },
			],
		},
		{
			questionText: ' Which of the following is the correct syntax of creating a standard navigation tab?',
			answerOptions: [
				{ answerText: '<ul class="nav nav-tabs">', isCorrect: true},
				{ answerText: '<ul class="navigation nav-tabs">', isCorrect: false },
				{ answerText: '<ul class="navigation tabs">', isCorrect: false },
				{ answerText: '<ul class="nav tab">', isCorrect: false },
			],
		},
		{
			questionText: 'Which type of JavaScript language is ',
			answerOptions: [
				{ answerText: 'Object-Oriented', isCorrect: false },
				{ answerText: 'Object-based', isCorrect: true },
				{ answerText: 'Assembly-language', isCorrect: false },
				{ answerText: 'High Level', isCorrect: true },
			],
		},
		{
			questionText: ' When there is an indefinite or an infinite value during an arithmetic computation in a program, then JavaScript prints',
			answerOptions: [
				{ answerText: 'Prints an exception error', isCorrect: false },
				{ answerText: 'Prints an overflow error', isCorrect: false },
				{ answerText: 'Prints the value as such', isCorrect: false },
				{ answerText: 'MaybeDisplays "Infinity"', isCorrect: true },
			],
		},
		{
			questionText: 'Which of the following givenfunctions of the Number Object formats a number with a different number of digits to the right of the decimal?',
			answerOptions: [
				{ answerText: 'toExponential()', isCorrect: false },
				{ answerText: 'toFixed()', isCorrect: true },
				{ answerText: 'toPrecision()', isCorrect: false },
				{ answerText: 'toLocaleString()', isCorrect: false },
			],
		},
	];

	const [currentQuestion, setCurrentQuestion] = useState(0);
	const [showScore, setShowScore] = useState(false);
	const [score, setScore] = useState(0);

	const handleAnswerOptionClick = (isCorrect) => {
		if (isCorrect) {
			setScore(score + 1);
		}

		const nextQuestion = currentQuestion + 1;
		if (nextQuestion < questions.length) {
			setCurrentQuestion(nextQuestion);
		} else {
			setShowScore(true);
		}
	};
	return (


		<div className='app'>
           
			{showScore ? (
				<div className='score-section'>
					You scored {score} out of {questions.length}
				</div>
			) : (
				<>
					<div className='question-section'>
						<div className='question-count'>
							<span>Question {currentQuestion + 1}</span>/{questions.length}
						</div>
						<div className='question-text'>{questions[currentQuestion].questionText}</div>
					</div>
					<div className='answer-section'>
						{questions[currentQuestion].answerOptions.map((answerOption) => (
							<button onClick={() => handleAnswerOptionClick(answerOption.isCorrect)}>{answerOption.answerText}</button>
						))}
					</div>
				</>
			)}
		</div>
   
	);
}
```

First of all , ignore the format of code.
Working - 
1. First we created an array of Questions which have Question and Their MCQ options as answers. This is the data we will work on.
2. Then we created 3 states for currentQuestion with 0 as initializing value , showScore as false and Score with 0 as initializing value.
3. Then we created an arrow function which first checks if the answer is correct then increment the value of score by 1, then it sets the next question as current question + 1(means if the current question is 1 then next question is 2).
4. The it checks that the next question exceeds the total number of questions of not , if next question do not exceed the total number of question then it set the current question as next question , else if the next question is greater than total question length , then it shows the score of the quiz.
5. Then in the UI Part we used the showScore state to show the score of the quiz , if the show score state is true , the score is shown to the display and if it is false then it will show the next question with options related to that question until all the questions has been shown and the set score state becomes false and show the score of the quiz.

CSS PART - 
```css
@import url('https://fonts.googleapis.com/css2?family=Bodoni+Moda&display=swap');



body
{
  /* background: linear-gradient(to right,rgb(130, 199, 222),cyan,rgb(93, 93, 191)); */
  background-image: url('https://wallpapercave.com/wp/wp4924046.jpg');
  background-size: cover;
  font-size: 8px;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  display: flex;
  justify-content: center;
  align-items: center;
  /* min-height: 100vh; */
  font-family: 'Bodoni Moda', serif;
}
.main
{
  display: flex;
  justify-content: space-evenly;
  flex-direction: column;
}

.app
{

  box-shadow: 10px 10px 42px 0px rgba(0, 0, 0, 0.75);
  display: flex;
  justify-content: space-evenly;
  width: 50rem;
  height: 25rem;
  border: 0.1rem solid rgb(29, 29, 87);
  border-radius: 0.3rem;
  min-height: 200px;
  color: white;
  background: #000000;  /* fallback for old browsers */
  background: -webkit-linear-gradient(to right, #434343, #000000);  /* Chrome 10-25, Safari 5.1-6 */
  background: linear-gradient(to right, #434343, #000000); /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */
  
}
.score-section

{
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 1rem;
  animation-name: score;
  animation-duration: 1s;
  animation-fill-mode: forwards;
  animation-delay: 0.2s;
}

.question-section
{
width: 100%;
position: relative;
padding: 0.5rem 2rem;

}
.question-count
{
  font-size: 1.3rem;
  font-weight: bolder;
  margin: 0.5rem 0;
}
.question-count span{
  font-size: 2rem;
}
.question-text
{
  font-size: 1.3rem;
  font-weight: bold;
}

/* ANSWERS/RIGHT SECTION */
.answer-section {
  width: 100%;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  margin: 1rem 1rem;
}

button {
  width: 100%;
  font-size: 16px;
  color: #ffffff;
  background-color: #252d4a;
  border-radius: 15px;
  display: flex;
  padding: 10px;
  justify-content: flex-start;
  align-items: center;
  border: 5px solid #234668;
  cursor: pointer;
}

.correct {
  background-color: #2f922f;
}

.incorrect {
  background-color: #ff3333;
}

button:hover {
  background-color: #555e7d;
}

button:focus {
  outline: none;
}

button svg {
  margin-right: 5px;
}

@keyframes score {

  100%
  {
    font-size: 3rem;
  }
}


.nav
{
  font-size: 1rem;
}
```

OUTPUT -
![Screenshot (6)](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/13egki2t7q0dgkq9lsux.png)

![Screenshot (7)](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hmvn33h7ftbx36p7vyei.png)
  


NOTE - We also used the bootstrap classes so add bootstrap also either using CDN or using npm

If you find any mistake or want to give suggestion to improve the code then please mention it in the comment section , it will help me a lot 

THANK YOU FOR READING THIS POST