React问答应用:实现答案点击选中保持及ID重复问题修复
问题修复与实现方案
1. 解决答案项ID重复问题
你当前用index作为答案列表项的key,且点击时传递index,但每个题目下的答案index都是0、1、2、3,导致不同题目的答案无法区分。解决方法:
- 用题目ID+答案文本作为唯一key,确保每个答案项的key全局唯一
- 点击时传递题目ID和当前答案文本,明确标记是哪道题的哪个选项被点击
2. 实现答案选中状态切换
需要在每个题目对象中添加selectedAnswer字段跟踪用户选择,点击时切换选中状态:
修改状态初始化
在fetchQuiz中,给每个题目对象新增selectedAnswer: null:
const updated = randomQuiz.map((item) => ({ ...item, selectedAnswer: null, // 跟踪用户选中的答案 }));
实现点击切换逻辑
更新answerClicked函数,根据题目ID和答案文本切换选中状态:
const answerClicked = (questionId, answer) => { setQuiz(prevQuiz => prevQuiz.map(quizItem => { if (quizItem.id === questionId) { // 若当前选中的就是该答案则取消选中,否则设置为选中 return { ...quizItem, selectedAnswer: quizItem.selectedAnswer === answer ? null : answer }; } return quizItem; })); };
渲染时添加选中样式
生成答案列表项时,判断当前答案是否为该题选中项,添加selected类:
const answerElements = item.answers.map((answer) => ( <li key={`${item.id}-${answer}`} // 唯一key className={`answer ${item.selectedAnswer === answer ? 'selected' : ''}`} onClick={() => answerClicked(item.id, answer)} > {answer} </li> ));
配套CSS样式:
.answer.selected { background-color: #4285F4; color: white; /* 可按需添加边框、内边距等样式 */ }
3. 统一检查答案实现
添加isChecked状态标记是否已检查答案,点击按钮后显示对错结果并禁用后续选择:
添加检查状态
const [isChecked, setIsChecked] = React.useState(false);
检查答案逻辑
实现检查按钮的点击事件:
const checkAnswers = () => { setIsChecked(true); // 统计答对数量(可选) const correctCount = quiz.filter(item => item.selectedAnswer === item.correctAnswer).length; console.log(`答对了${correctCount}题`); };
渲染时显示对错结果
修改答案列表项渲染逻辑,根据检查状态显示正确/错误样式:
const answerElements = item.answers.map((answer) => { let answerClass = 'answer'; if (isChecked) { if (answer === item.correctAnswer) { answerClass += ' correct'; // 正确答案样式 } else if (answer === item.selectedAnswer) { answerClass += ' wrong'; // 用户选错的样式 } } else if (item.selectedAnswer === answer) { answerClass += ' selected'; // 未检查时的选中样式 } return ( <li key={`${item.id}-${answer}`} className={answerClass} onClick={() => !isChecked && answerClicked(item.id, answer)} // 检查后禁用点击 > {answer} </li> ); });
配套CSS样式:
.answer.correct { background-color: #34A853; color: white; } .answer.wrong { background-color: #EA4335; color: white; }
更新检查按钮
<button onClick={checkAnswers} disabled={isChecked}> {isChecked ? '已检查答案' : '检查答案'} </button>
完整修改后的组件代码
import React from "react"; import { Link } from "react-router-dom"; export default function Game() { const [quiz, setQuiz] = React.useState([]); const [isChecked, setIsChecked] = React.useState(false); function shuffle(array) { for (let i = array.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [array[i], array[j]] = [array[j], array[i]]; } return array; } const fetchQuiz = async () => { const res = await fetch( "https://the-trivia-api.com/api/questions?limit=5" ); const randomQuiz = await res.json(); const updated = randomQuiz.map((item) => ({ ...item, selectedAnswer: null, // 跟踪用户选中的答案 })); const shuffledQuiz = updated.map((item) => { const answers = [...item.incorrectAnswers, item.correctAnswer]; const shuffledAnswers = shuffle(answers); return { ...item, answers: shuffledAnswers }; }); setQuiz(shuffledQuiz); }; React.useEffect(() => { fetchQuiz(); }, []); const answerClicked = (questionId, answer) => { setQuiz(prevQuiz => prevQuiz.map(quizItem => { if (quizItem.id === questionId) { return { ...quizItem, selectedAnswer: quizItem.selectedAnswer === answer ? null : answer }; } return quizItem; })); }; const checkAnswers = () => { setIsChecked(true); const correctCount = quiz.filter(item => item.selectedAnswer === item.correctAnswer).length; console.log(`答对了${correctCount}题`); }; let block = quiz.map((item) => { const answerElements = item.answers.map((answer) => { let answerClass = 'answer'; if (isChecked) { if (answer === item.correctAnswer) { answerClass += ' correct'; } else if (answer === item.selectedAnswer) { answerClass += ' wrong'; } } else if (item.selectedAnswer === answer) { answerClass += ' selected'; } return ( <li key={`${item.id}-${answer}`} className={answerClass} onClick={() => !isChecked && answerClicked(item.id, answer)} > {answer} </li> ); }); return ( <div key={item.id} className="quiz_block"> <h1 className="quiz_question">{item.question}</h1> <ul className="quiz_answers">{answerElements}</ul> </div> ); }); return ( <main> <div className="game_container"> {block} <div className="footer"> <button onClick={checkAnswers} disabled={isChecked}> {isChecked ? '已检查答案' : '检查答案'} </button> </div> </div> </main> ); }
内容的提问来源于stack exchange,提问作者Play
相关产品推荐
相关产品推荐

