You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 10:27:40