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
optionsas an Array instead ofathroughd, and the selected answer as theindexfrom0to3. 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 optionalselectedattribute, and pass in additionalselectedStylesattribute 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
answerstate 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 withspanordivfor semantic correctness.Simplify Styling Function: Move common styles like
color: "#000000"to CSS to simplify thestylerfunction.