In this post, I’ll walk through how I created a basic quiz application using React. The goal of this app is to let users enter their name, take a multiple-choice quiz, and see their result at the end. I used React hooks and the Context API to manage global state like username, score, and gamestate.
Folder Structure
src/
├── App.js
├── App.css
├── assets/
│ └── questions.json
├── components/
│ ├── User.js
│ ├── Quiz.js
│ └── Result.js
App.js
import logo from './logo.svg';
import './App.css';
import User from './components/User';
import Quiz from './components/Quiz';
import Result from './components/Result';
import { createContext, useEffect, useState } from 'react';
export const quizContext = createContext();
function App() {
const [gamestate, setGamestate] = useState("users");
const [username, setUsername] = useState("");
const [score, setScore] = useState(0);
return (
<div className="App">
<header className="App-header">
<quizContext.Provider value={{ gamestate, setGamestate, username, setUsername, score, setScore }}>
{gamestate === 'users' && <User />}
{gamestate === 'playing' && <Quiz />}
{gamestate === 'result' && <Result />}
</quizContext.Provider>
</header>
</div>
);
}
export default App;
User.js
import React, { useContext, useEffect, useRef } from 'react';
import { quizContext } from '../App';
function User() {
const { gamestate, setGamestate, username, setUsername } = useContext(quizContext);
const userRef = useRef();
useEffect(() => {
userRef.current.focus();
}, []);
function startPlaying() {
setUsername(userRef.current.value);
setGamestate("playing");
}
return (
<div>
<input type="text" placeholder='Enter useName' ref={userRef} />
<button onClick={startPlaying}>Start Quiz</button>
</div>
);
}
export default User;
Quiz.js
import React, { useContext, useState } from 'react';
import questions from '../assets/questions.json';
import { quizContext } from '../App';
function Quiz() {
const [currentQuestion, setCurrentQuestion] = useState(0);
const [optionChosen, setOptionChosen] = useState("");
const { setGamestate, score, setScore } = useContext(quizContext);
function next() {
if (optionChosen === questions[currentQuestion]['answer']) {
setScore(score + 1);
}
setCurrentQuestion(currentQuestion + 1);
setOptionChosen("");
}
function finish() {
if (optionChosen === questions[currentQuestion]['answer']) {
setScore(score + 1);
}
setGamestate("result");
}
return (
<div>
{questions[currentQuestion]['prompt']}
{
['A', 'B', 'C', 'D'].map((opt) => (
<button onClick={() => setOptionChosen(`option${opt}`)}>
{questions[currentQuestion][`option${opt}`]}
</button>
))
}
{
(questions.length - 1 === currentQuestion)
? (<button onClick={finish}>Finish</button>)
: (<button onClick={next}>Next</button>)
}
</div>
);
}
export default Quiz;
Result.js
import React, { useContext } from 'react';
import { quizContext } from '../App';
import questions from '../assets/questions.json';
function Result() {
const { setGamestate, setUsername, score, username, setScore } = useContext(quizContext);
function restartQuiz() {
setUsername("");
setScore(0);
setGamestate("users");
}
return (
<div>
<h1>{`${username} scored ${score} out of ${questions.length}`}</h1>
<button onClick={restartQuiz}>Restart Quiz</button>
</div>
);
}
export default Result;
questions.json
[
{
"prompt": "HTML stands for?",
"optionA": "HyperText Markup Language",
"optionB": "HyperText Mark Language",
"optionC": "HyperText Markup Learn",
"optionD": "Hyper Markup Language",
"answer": "optionA"
},
{
"prompt": "JS stands for?",
"optionA": "HyperText Markup Language",
"optionB": "CSS",
"optionC": "TypeScript",
"optionD": "JavaScript",
"answer": "optionD"
},
{
"prompt": "CSS stands for?",
"optionA": "Cascading Style Sheets",
"optionB": "Cascading Sheet Styles",
"optionC": "Colorful Style Sheets",
"optionD": "Computer Style Sheets",
"answer": "optionA"
},
{
"prompt": "Which HTML element is used for the largest heading?",
"optionA": "<h1>",
"optionB": "<h2>",
"optionC": "<h3>",
"optionD": "<h4>",
"answer": "optionA"
},
{
"prompt": "Which symbol is used to select classes in CSS?",
"optionA": "#",
"optionB": ".",
"optionC": "*",
"optionD": "&",
"answer": "optionB"
}
]
What I Learned
- Using
useRef
for managing input focus - Conditional rendering based on state
- Managing global state using Context API
- Handling multiple components that rely on shared state
- Loading data dynamically from a JSON file
Top comments (0)