如何为Quiz应用设置统一提交按钮,替代每题单独判分?
实现统一判分的修改方案
要实现所有题目选完后统一判分,需要把选中状态和结果展示的控制权从单个Question组件转移到App组件,让App统一管理所有题目的选择和结果展示逻辑。具体修改步骤如下:
1. 修改App.js,统一管理状态与结果计算
- 新增
userAnswers状态,存储每道题的选中答案 - 新增
showResults状态,控制是否展示判分结果 - 给Question组件传递选中答案、选择回调、是否显示结果的props
- 完善
checkResult函数,计算得分并触发结果展示
修改后的App.js代码:
import { React, useState, useEffect } from 'react' import './App.css'; import Question from './components/Question' function App(){ const [getQuestions, setGetQuestions] = useState([]) const [start, setStart] = useState(false) // 存储用户每道题的选中答案,key为题目内容,value为选中的选项 const [userAnswers, setUserAnswers] = useState({}) // 控制是否显示判分结果 const [showResults, setShowResults] = useState(false) useEffect(function(){ async function getQuestionsFromApi(){ const res = await fetch(`https://opentdb.com/api.php?amount=5`) const data = await res.json() setGetQuestions(data.results) } getQuestionsFromApi() },[]) // 处理用户选择答案的回调函数 const handleAnswerSelect = (question, selectedOption) => { setUserAnswers(prev => ({ ...prev, [question]: selectedOption })) } const displayQuestions = getQuestions.map( element => <Question key={element.question} question={element.question} correct_answer={element.correct_answer} incorrect_answers={element.incorrect_answers} // 传递当前题目的选中答案 selectedOption={userAnswers[element.question]} // 传递选择答案的回调 onSelect={handleAnswerSelect} // 传递是否显示结果的状态 showResults={showResults} /> ) function gameStart(){ setStart(true) // 开始游戏时重置状态 setUserAnswers({}) setShowResults(false) } function checkResult(){ // 计算答对的题目数量 const correctCount = getQuestions.filter( q => userAnswers[q.question] === q.correct_answer ).length console.log(`你答对了${correctCount}/${getQuestions.length}题`) // 触发结果展示 setShowResults(true) } // 检查是否所有题目都已作答 const allAnswered = getQuestions.every(q => userAnswers.hasOwnProperty(q.question)) return( <> {start ? <div> {displayQuestions} {/* 只有所有题目都作答后才启用按钮 */} <button className='result--button' onClick={checkResult} disabled={!allAnswered} > Check the Answers </button> {/* 显示得分结果 */} {showResults && ( <div className="score"> 你答对了 {getQuestions.filter(q => userAnswers[q.question] === q.correct_answer).length} / {getQuestions.length} 题 </div> )} </div> : <div className="home--page"> <h1>Quizzical</h1> <p>some description if needed</p> <button className='start' onClick={gameStart} >Start quiz</button> </div> } </> ) } export default App
2. 修改Question.js,依赖父组件传递的props
- 移除组件内部的
selectedOption状态,改用父组件传递的同名props - 修改
handleSelect函数,仅在showResults为true时判断对错样式 - 修改点击事件,调用父组件传递的
onSelect回调 - 调整按钮禁用逻辑:未显示结果时,选中后禁用;显示结果时全部禁用
修改后的Question.js代码:
import { React, useState, useEffect } from 'react' import './Question.css' function Question({question, correct_answer, incorrect_answers, selectedOption, onSelect, showResults}){ const [options, setOptions] = useState([]) useEffect(function(){ const arr = [...incorrect_answers, correct_answer] // 随机打乱选项顺序(可选优化,避免正确答案固定位置) arr.sort(() => Math.random() - 0.5) setOptions(arr) }, [incorrect_answers, correct_answer]) function handleSelect(element){ if (!showResults) { // 未显示结果时,只高亮选中的选项 return selectedOption === element ? 'selected' : '' } else { // 显示结果时,区分正确/错误/未选中 if (element === correct_answer) { return 'select' } else if (selectedOption === element) { return 'wrong' } else { return 'grey' } } } function handleClick(element){ // 调用父组件的回调,传递题目和选中选项 onSelect(question, element) } const displayOptions = options.map(element => <button className={handleSelect(element)} key={element} onClick={() => handleClick(element)} disabled={showResults || (selectedOption !== undefined && selectedOption !== element)} > {element} </button> ) return( <> <div className='question--container'> <h1> {question} </h1> {displayOptions} </div> </> ) } export default Question
关键逻辑说明
- 状态提升:把用户的选择从Question组件转移到App组件,让App可以统一获取所有题目的答案并计算得分。
- 结果展示控制:通过
showResults状态控制是否展示对错样式,只有点击判分按钮后才触发高亮。 - 按钮可用性:只有所有题目都作答后,判分按钮才会启用,避免用户未完成答题就点击判分。
内容的提问来源于stack exchange,提问作者gerard
相关产品推荐
相关产品推荐

