React+Redux开发MCQS测验:提交表单时对比单选输入与正确答案
嘿,我来帮你搞定这个React+Redux测验应用的答案比对问题!咱们一步步来,从数据结构到Redux状态管理,再到组件交互,逻辑清晰又好维护。
1. 先统一你的数据结构(关键前提)
首先得保证Data.js里的测验题和Answers.js里的正确答案能对应上,最稳妥的方式是用题目ID作为关联键。举个例子:
Data.js的结构(每个题目带唯一id):
export default [ { id: 'q1', questionText: 'React是哪个公司开发的?', options: [ { value: 'a', label: 'Google' }, { value: 'b', label: 'Facebook' }, { value: 'c', label: 'Microsoft' }, ], }, { id: 'q2', questionText: 'Redux的核心原则不包括以下哪项?', options: [ { value: 'a', label: '单一数据源' }, { value: 'b', label: '状态可突变' }, { value: 'c', label: '纯函数修改状态' }, ], }, // 更多题目... ];
Answers.js的结构(键是题目id,值是正确选项的value):
export default { 'q1': 'b', 'q2': 'b', // 对应每个题目的正确选项值 };
2. 用Redux管理用户答案与得分
推荐用Redux Toolkit(现在React生态的标准方案)来创建状态切片,专门处理测验相关的状态:
创建测验状态切片(quizSlice.js)
这里我们定义存储用户答案、计算得分的逻辑:
import { createSlice } from '@reduxjs/toolkit'; const initialState = { userAnswers: {}, // 存储用户选择:{ [questionId]: selectedOptionValue } score: 0, answerResults: {}, // 可选:存储每道题的对错详情 }; const quizSlice = createSlice({ name: 'quiz', initialState, reducers: { // 记录用户的单题选择 setUserAnswer: (state, action) => { const { questionId, selectedOption } = action.payload; state.userAnswers[questionId] = selectedOption; }, // 提交时比对答案、计算得分 calculateScore: (state, action) => { const correctAnswers = action.payload; let score = 0; const answerResults = {}; // 遍历用户答案,和正确答案逐一比对 Object.keys(state.userAnswers).forEach(questionId => { const userChoice = state.userAnswers[questionId]; const correctChoice = correctAnswers[questionId]; const isCorrect = userChoice === correctChoice; if (isCorrect) score++; // 记录每道题的比对结果(可选) answerResults[questionId] = { userChoice, correctChoice, isCorrect, }; }); state.score = score; state.answerResults = answerResults; }, // 重置测验状态 resetQuiz: (state) => { state.userAnswers = {}; state.score = 0; state.answerResults = {}; }, }, }); export const { setUserAnswer, calculateScore, resetQuiz } = quizSlice.actions; export default quizSlice.reducer;
把切片加入Redux Store(store.js)
import { configureStore } from '@reduxjs/toolkit'; import quizReducer from './quizSlice'; export const store = configureStore({ reducer: { quiz: quizReducer, }, });
3. React组件中处理单选按钮与提交逻辑
单题组件(QuizQuestion.js)
负责渲染单个题目和单选按钮,用户选择时同步到Redux状态:
import { useDispatch } from 'react-redux'; import { setUserAnswer } from './quizSlice'; const QuizQuestion = ({ question }) => { const dispatch = useDispatch(); const handleOptionChange = (e) => { // 把用户选择的题目ID和选项值发给Redux dispatch(setUserAnswer({ questionId: question.id, selectedOption: e.target.value, })); }; return ( <div className="question-card"> <h3>{question.questionText}</h3> {question.options.map(option => ( <div key={option.value} className="option-item"> <input type="radio" id={`q-${question.id}-opt-${option.value}`} name={`question-${question.id}`} value={option.value} onChange={handleOptionChange} /> <label htmlFor={`q-${question.id}-opt-${option.value}`}> {option.label} </label> </div> ))} </div> ); }; export default QuizQuestion;
主测验组件(Quiz.js)
渲染所有题目,处理提交按钮,触发答案比对逻辑:
import { useSelector, useDispatch } from 'react-redux'; import QuizQuestion from './QuizQuestion'; import { calculateScore, resetQuiz } from './quizSlice'; import mcqsData from './Data'; import correctAnswers from './Answers'; const Quiz = () => { const { userAnswers, score, answerResults } = useSelector(state => state.quiz); const dispatch = useDispatch(); const handleSubmit = (e) => { e.preventDefault(); // 可选:检查用户是否答完所有题目 if (Object.keys(userAnswers).length !== mcqsData.length) { alert('请完成所有题目再提交哦!'); return; } // 触发Redux里的答案比对与得分计算 dispatch(calculateScore(correctAnswers)); }; const handleReset = () => { dispatch(resetQuiz()); }; return ( <div className="quiz-container"> <form onSubmit={handleSubmit}> {mcqsData.map(question => ( <QuizQuestion key={question.id} question={question} /> ))} <div className="action-buttons"> <button type="submit">提交答案</button> <button type="button" onClick={handleReset}>重新开始</button> </div> </form> {/* 显示得分与答题结果 */} {score !== 0 && ( <div className="result-section"> <h2>你的得分:{score}/{mcqsData.length}</h2> <div className="answer-details"> {mcqsData.map(question => { const result = answerResults[question.id]; return ( <div key={question.id} className={`answer-item ${result.isCorrect ? 'correct' : 'wrong'}`}> <p>{question.questionText}</p> <p>你的选择:{result.userChoice}</p> <p>正确答案:{result.correctChoice}</p> </div> ); })} </div> </div> )} </div> ); }; export default Quiz;
4. 核心逻辑说明
当用户点击提交按钮时,我们把Answers.js里的正确答案作为参数传给Redux的calculateScore action,在reducer里遍历用户的答案对象,通过题目ID匹配对应的正确答案,逐一比对后计算得分。如果需要展示每道题的对错,还可以把比对结果存在Redux状态里,在组件中渲染出来。
内容的提问来源于stack exchange,提问作者Mubi
相关产品推荐
相关产品推荐

