I built a simple trivia with React from Vite that reads from an external JS file.
Here is the main code for the game:
import { useState } from "react";
import "./App.css";
import { questions } from "./assets/newquestions";
const App = () => {
const [answer, setAnswer] = useState("");
const [count, setCount] = useState(0);
const styler = (choice) => {
if (answer) {
if (choice === questions[count].answer) {
return { backgroundColor: "#00FF00", color: "#000000" };
} else {
return { backgroundColor: "#FF0000", color: "#000000" };
}
}
};
return (
<>
<h1>
{count}) {questions[count].question}
</h1>
<div className="card">
<button
style={styler("A")}
onClick={() => setAnswer("A")}
disabled={answer !== ""}
>
<h2>A) {questions[count].A}</h2>
</button>
<button
style={styler("B")}
onClick={() => setAnswer("B")}
disabled={answer !== ""}
>
<h2>B) {questions[count].B}</h2>
</button>
</div>
<div className="card">
<button
style={styler("C")}
onClick={() => setAnswer("C")}
disabled={answer !== ""}
>
<h2>C) {questions[count].C}</h2>
</button>
<button
style={styler("D")}
onClick={() => setAnswer("D")}
disabled={answer !== ""}
>
<h2>D) {questions[count].D}</h2>
</button>
</div>
{answer ? (
<button
onClick={() => {
setAnswer("");
setCount(count + 1);
}}
>
Next Question
</button>
) : null}
</>
);
};
export default App;
Here is an small snippet of the question code:
export const questions = [
{
difficulty: "0",
question: "Are you ready to start?",
A: "Yes",
B: "No",
C: "No",
D: "No",
answer: "A",
},
{
difficulty: "1",
question: "Which artist painted the Mona Lisa?",
A: "Picasso",
B: "Leonardo Da Vinci",
C: "Andy Warhol",
D: "Aaron Van Kampen",
answer: "B",
},
...
2 Answers 2
With React, it's important to identify and separate what requires and what doesn't require state
. In this scenario, the presentation of the questions and answers is mainly stateless while the selected question, and assessment of the answer are stateful. The one edge-case is indicating whether they answered correctly vs incorrectly.
My recommendations are:
- Redefine the data model to specify
options
as an Array instead ofa
throughd
, and the selected answer as theindex
from0
to3
. This allows you to use a loop to render the options, which are identical and don't need to be repeated. This also allows you to generalize to more answers, for some questions, and potentially multiple answers in the future. - Extract a presentational component that is stateless that displays the options. Bubble up an event for when an option is
selected
, pass in an optionalselected
attribute, and pass in additionalselectedStyles
attribute for showing the highlight when the answer is assessed. - Consider using more semantic HTML elements such as
input type="radio"
to present the cards so that its more accessible.
I also noticed that you are using difficulty
in the model but are not presenting it or using it in your assessment as well. I'd recommend removing that if its not being used, and if it is, consider changing it to a number.
Some suggestions after reviewing your code:
Use Enums for Choices: Replace hardcoded "A", "B", "C", "D" with an enum for readability.
DRY (Don't Repeat Yourself): Use a map function to generate button elements and make your code DRYer.
Reset State: Reset the
answer
state when moving to the next question to avoid carrying over styles.Boundary Check: Add a condition to handle the end of the questions array.
Semantic HTML: Replace
<h2>
inside buttons withspan
ordiv
for semantic correctness.Simplify Styling Function: Move common styles like
color: "#000000"
to CSS to simplify thestyler
function.