React组件状态修改问题:答题按钮点击后背景不更新
问题描述
我正在开发一款测验应用,遇到以下问题:
- 用户点击答案按钮时,无法修改按钮背景色,
holdAnswer函数能打印答案ID,但无法修改对应答案的状态 - 需要存储用户所选答案以统计答题数量,后续还要根据答案对错进行高亮,这些都需要修改组件状态
App.js
import { useState } from "react"; import QuestionSet from "./QuestionSet"; import Answers from "./Answers"; import { nanoid } from "nanoid"; function App() { const [isQuesLoaded, setIsQuesLoaded] = useState(false); const [questions, setQuestions] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); async function startQuiz() { try { setIsQuesLoaded(!isQuesLoaded); const response = await fetch( "https://opentdb.com/api.php?amount=5&category=12&difficulty=easy&type=multiple" ); const data = await response.json(); const allQuestions = data.results; const listOfQuestions = allQuestions.map((item) => { const allAnswers = [ { id: nanoid(), isCorrect: false, isChosen: false, answer: item.incorrect_answers[0], }, { id: nanoid(), isCorrect: false, isChosen: false, answer: item.incorrect_answers[1], }, { id: nanoid(), isCorrect: false, isChosen: false, answer: item.incorrect_answers[2], }, { id: nanoid(), isCorrect: true, isChosen: false, answer: item.correct_answer, }, ]; return { id: nanoid(), question: item.question, answers: allAnswers, }; }); setQuestions(listOfQuestions); } catch (err) { setError(err.message); } finally { setLoading(false); } } function holdAnswer(id) { console.log(id); setQuestions((prevQuestion) => prevQuestion.map((question) => question.answers.id === id ? { ...question, answers: question.answers.map((answer) => answer.id === id ? { ...answer, isChosen: !answer.isChosen } : answer ), } : question ) ); } const questionElm = questions.map((question, index) => { return ( <section key={index}> <QuestionSet question={question.question} key={question.id} /> <Answers answers={question.answers} isChosen={question.answers.isChosen} holdAnswer={holdAnswer} /> </section> ); }); return ( <div className="App"> {!isQuesLoaded ? ( <main> <h1 className="title-app">Quizzical</h1> <p className="desc-app">Some description if needed</p> <button className="btn" onClick={startQuiz}> Start Quiz </button> </main> ) : ( <main className="quest-box"> {loading && <div>Loading data...</div>} {error && <div>{`There is a problem fetchning data = ${error}`}</div>} <section className="quest-content">{questionElm}</section> <button className="answer-btn">Check Answers</button> </main> )} </div> ); } export default App;
Answers.js
export default function Answers(props) { const styles = { backgroundColor: props.answers.isChosen ? "#D6DBF5" : "transparent", }; return ( <section className="answer-container"> <div className="answer-div" style={styles} id={props.answers[3].id} onClick={() => props.holdAnswer(props.answers[3].id)} > <p>{props.answers[3].answer}</p> </div> <div className="answer-div" style={styles} id={props.answers[1].id} onClick={() => props.holdAnswer(props.answers[1].id)} > <p>{props.answers[1].answer}</p> </div> <div className="answer-div" style={styles} id={props.answers[2].id} onClick={() => props.holdAnswer(props.answers[2].id)} > <p>{props.answers[2].answer}</p> </div> <div className="answer-div" style={styles} id={props.answers[0].id} onClick={() => props.holdAnswer(props.answers[0].id)} > <p>{props.answers[0].answer}</p> </div> </section> ); }
解决方案
1. 修复holdAnswer状态更新逻辑
原代码中question.answers.id === id判断错误,question.answers是数组,没有id属性。修改为直接遍历每个问题的答案数组,匹配ID切换状态:
function holdAnswer(id) { setQuestions((prevQuestions) => prevQuestions.map((question) => ({ ...question, answers: question.answers.map((answer) => answer.id === id ? { ...answer, isChosen: !answer.isChosen } : answer ) })) ); }
2. 修复Answers组件样式绑定与渲染逻辑
原代码中props.answers.isChosen无效(数组无此属性),且硬编码答案索引不灵活。改为循环渲染每个答案,绑定对应isChosen状态:
export default function Answers(props) { return ( <section className="answer-container"> {props.answers.map((answer) => ( <div key={answer.id} className="answer-div" style={{ backgroundColor: answer.isChosen ? "#D6DBF5" : "transparent" }} onClick={() => props.holdAnswer(answer.id)} > <p>{answer.answer}</p> </div> ))} </section> ); }
3. 移除无效props传递
App组件中传递给Answers的isChosen={question.answers.isChosen}无效,直接删除该属性:
<Answers answers={question.answers} holdAnswer={holdAnswer} />
4. 统计答题数量
通过遍历questions数组统计已选择的答案数量:
// 在App组件中添加统计逻辑 const answeredCount = questions.reduce((count, question) => { return count + question.answers.filter(answer => answer.isChosen).length; }, 0);
5. 答案对错高亮
新增状态控制结果显示,点击按钮后切换状态,根据答案的isCorrect和isChosen渲染不同背景色:
- 在App组件中添加状态:
const [showResults, setShowResults] = useState(false);
- 修改"Check Answers"按钮:
<button className="answer-btn" onClick={() => setShowResults(true)} > Check Answers </button>
- 传递状态给Answers组件:
<Answers answers={question.answers} holdAnswer={holdAnswer} showResults={showResults} />
- 修改Answers组件样式逻辑:
style={{ backgroundColor: props.showResults ? answer.isCorrect ? "#94D7A2" // 正确答案绿色 : answer.isChosen ? "#F8BCBC" // 选错答案红色 : "transparent" : answer.isChosen ? "#D6DBF5" // 选中状态蓝色 : "transparent" }}
内容的提问来源于stack exchange,提问作者lsokol
相关产品推荐
相关产品推荐

