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

React.js测验应用中如何保存单选按钮选中状态

问题分析与解决方案

你的核心问题在于直接操作DOM控制单选框选中状态,这和React状态驱动UI的理念冲突,加上状态更新的异步特性,导致选中状态混乱。下面是修复方案,完全用React状态管理实现单选框的状态保持:

关键问题点

  1. 用document.querySelectorAll手动设置checked属性,会和React受控组件机制冲突,造成状态不同步。
  2. setCurrent是异步操作,handlePrevious中访问current时仍是旧值,导致读取错误的题目答案。
  3. handlerSave中用push存储答案到localStorage,会导致重复存储,无法正确对应题目索引。

修复后的完整代码

import React, { useState, useEffect } from 'react'
import Result from './Result'
import './Exam.css'

function Exam() {
  const data = JSON.parse(localStorage.getItem('Que')) || []
  const savedAnswers = JSON.parse(localStorage.getItem('Ans')) || []

  // 初始化用户答案数组,长度匹配题目数量,缺省值为空字符串
  const [userAnswers, setUserAnswers] = useState(() => 
    Array(data.length).fill('').map((_, idx) => savedAnswers[idx] || '')
  )
  const [current, setCurrent] = useState(0)
  const [exit, setExit] = useState(false)
  const [correctCount, setCorrectCount] = useState(0)

  // 用户答案变化时同步更新到localStorage
  useEffect(() => {
    localStorage.setItem('Ans', JSON.stringify(userAnswers))
  }, [userAnswers])

  // 测验结束时统一计算正确答案数量
  useEffect(() => {
    if (exit) {
      const count = userAnswers.reduce((total, ans, idx) => {
        return ans === data[idx]?.answer ? total + 1 : total
      }, 0)
      setCorrectCount(count)
    }
  }, [exit, userAnswers, data])

  const handleAnswerChange = (e) => {
    const newAnswers = [...userAnswers]
    newAnswers[current] = e.target.value
    setUserAnswers(newAnswers)
  }

  const handlePrevious = () => {
    if (current > 0) {
      setCurrent(current - 1)
    }
  }

  const handleSaveNext = () => {
    if (current + 1 === data.length) {
      setExit(true)
    } else {
      setCurrent(current + 1)
    }
  }

  if (!data.length) {
    return <div>No questions found!</div>
  }

  return(
    <div>
      {!exit ? (
        <div className='mcq'>
          <div>
            Question :<span className='span'>{current + 1}</span>    
            {data[current].question}?
          </div><br/>
          <div>
            <div className='option'>
              <input 
                type='radio' 
                value='A' 
                name={`question-${current}`} // 每个题目用独立name,避免单选框组冲突
                onChange={handleAnswerChange} 
                checked={userAnswers[current] === 'A'}
                className='radioButton'
              /> 
              {data[current].A} 
            </div>
            <div className='option'>
              <input 
                type='radio' 
                value='B' 
                name={`question-${current}`}
                onChange={handleAnswerChange} 
                checked={userAnswers[current] === 'B'}
                className='radioButton'
              /> 
              {data[current].B} 
            </div>
            <div className='option'>
              <input 
                type='radio' 
                value='C' 
                name={`question-${current}`}
                onChange={handleAnswerChange} 
                checked={userAnswers[current] === 'C'}
                className='radioButton'
              /> 
              {data[current].C} 
            </div>
            <div className='option'>
              <input 
                type='radio' 
                value='D' 
                name={`question-${current}`}
                onChange={handleAnswerChange} 
                checked={userAnswers[current] === 'D'}
                className='radioButton'
              /> 
              {data[current].D} 
            </div>
          </div><br/>
          <div>
            {current !== 0 && <button onClick={handlePrevious}>Previous</button>}
            <button onClick={handleSaveNext}>Save & Next</button>
          </div>
        </div>
      ) : (
        <Result props={{correct: correctCount}}/>
      )}
    </div>
  )
}

export default Exam;

核心改进说明

  1. 受控组件实现:每个单选框的checked属性由userAnswers[current]直接控制,完全由React状态驱动,无需手动操作DOM。
  2. 独立单选框组:给每个题目设置唯一name(question-${current}),避免不同题目间的单选框互相干扰。
  3. 正确答案存储:用数组userAnswers对应题目索引,同步更新到localStorage,确保每个题目答案位置准确,无重复存储。
  4. 异步状态处理:移除所有DOM操作,利用React状态更新自动触发UI重渲染,避免异步状态导致的索引错误。
  5. 统一计算正确数:测验结束时统一统计正确答案数量,避免用户返回修改答案导致的计数偏差。

内容的提问来源于stack exchange,提问作者jenish963

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 17:35:12