如何优化React.js中的测试按钮



我正在建设一个测验应用程序。我已经建好了。但到目前为止,我对我的代码并不满意。我认为代码没有足够的可扩展性和简洁性。我想知道你是否能帮我把我的代码做得更好。

我需要的是,当用户点击其中一个选项,如果它是正确的,然后使按钮点击成绿色背景。否则,红色和正确按钮变为绿色。目前,它正在正常运转。但让我们假设,我必须有超过2个选项的问题,比如3个,5个,甚至更多。那么,这段代码将无法工作。逻辑变得更加丑陋。

你能帮我一下吗?

const questions = [
{
id: 1,
question: "which one of them is fruit?",
options: ["apple", "rice"],
answers: ["correct", "wrong"]
},
]
function App() {
const [btnA, setBtnA] = React.useState("gray")
const [btnB, setBtnB] = React.useState("gray")
const handleButtonA = (e, answer) => {
e.preventDefault()
if(answer == "correct") {
setBtnA("green");
}
if(answer === "wrong") {
setBtnA("red")
setBtnB("green")
}
}
const handleButtonB = (e, answer) => {
e.preventDefault();
if(answer === "correct") {
setBtnB("green")
}
if(answer === "wrong") {
setBtnA("green")
setBtnB("red")
}
}
return (
<div className="App">
{questions.map(q => {
return (
<div key={q.id}>
<h3>{q.question}</h3>
<button style={{background: btnA}} onClick={e => handleButtonA(e, q.answers[0])}>{q.options[0]}</button>
<button style={{background: btnB}} onClick={e => handleButtonB(e, q.answers[1])}>{q.options[1]}</button>
</div>
)
})}
</div>
);
}

首先,您的代码无法处理多个问题。由于所有按钮都共享相同的状态,因此单击对/错按钮将更新所有按钮。

第二,我建议你从这改变:

options: ["apple", "rice"],
answers: ["correct", "wrong"]

:

options: [
"apple",
"rice",
],
correct: 0

Where correct表示索引是正确的选项。这样你就不需要检查是否有字符串,而且一般来说,它更有方向性。

现在,我们不需要知道状态中的颜色,我们只需要知道问题是否被尝试过。为此,我们可以创建一个数组形式的状态。

const [quizData, setQuizData] = useState(questions.map(question => { 
return {
attempted: -1
}
}))

现在,我们终于可以遍历数组中的每个元素了。

return (
<div className="App">
{questions.map((q, questionIndex) => {
const currData = quizData[questionIndex];

// Method to handle when button is clicked
// valid is weather the question clicked was valid
const handleClick = (index) => {

// we use a method which recieves the currentState when using setState
// in order to prevent react scheduling issues
setQuizData((prevData) => {
// for the current question, set attempted to true
prevData[questionIndex].attempted = index;

// destructure the array because react doesnt work well with returning the same object instance
return [
...prevData
]
})
}
return (
<div key={q.id}>
<h3>{q.question}</h3>
{/* Looop over each option */}
{question.options.map((option, index) => {

// take gray as the default color
let color = "gray";

// if the user has attempted already, check to change the color
if (currData.attempted >= 0) {
if (index == currData.attempted) {
if (index == q.correct) {
color = "green";
}
else {
color = "red"
}
}
else if (index == q.correct) {
color = "greeen"
}
}

// over here the button's enabled property is something I added, but you can remove that if you'd like
return (
<button
enabled={!currData.attempted}
key={index}
style={{background: color}}
onClick={() => handleClick(index)}>
{option}
</button>
)
}}
</div>
)
})}
</div>
);
所以最后,我们的代码是:
const questions = [
{
id: 1,
question: "which one of them is fruit?",
options: [
"apple",
"rice",
],
correct: 0
},
]
function App() {
const [quizData, setQuizData] = useState(questions.map(question => { 
return {
attempted: -1
}
}))

return (
<div className="App">
{questions.map((q, questionIndex) => {
const currData = quizData[questionIndex];
// Method to handle when button is clicked
// valid is weather the question clicked was valid
const handleClick = (index) => {
// we use a method which recieves the currentState when using setState
// in order to prevent react scheduling issues
setQuizData((prevData) => {
// for the current question, set attempted to true
prevData[questionIndex].attempted = index;
// destructure the array because react doesnt work well with returning the same object instance
return [
...prevData
]
})
}
return (
<div key={q.id}>
<h3>{q.question}</h3>
{/* Looop over each option */}
{question.options.map((option, index) => {
// take gray as the default color
let color = "gray";
// if the user has attempted already, check to change the color
if (currData.attempted >= 0) {
if (index == currData.attempted) {
if (index == q.correct) {
color = "green";
}
else {
color = "red"
}
}
else if (index == q.correct) {
color = "greeen"
}
}
// over here the button's enabled property is something I added, but you can remove that if you'd like
return (
<button
enabled={!currData.attempted}
key={index}
style={{background: color}}
onClick={() => handleClick(index)}>
{option}
</button>
)
}}
</div>
)
})}
</div>
);

最新更新