Shadcn 的 RadioGroup 在分页问卷中出现「前一题答案被错误复用到后一题」的问题,根本原因是未显式控制 RadioGroupItem 的 checked 属性;修复关键在于为每个选项项手动绑定 checked={value === savedAnswer},而非仅依赖 RadioGroup 的 value。
shadcn 的 `radiogroup` 在分页问卷中出现「前一题答案被错误复用到后一题」的问题,根本原因是未显式控制 `radiogroupitem` 的 `checked` 属性;修复关键在于为每个选项项手动绑定 `checked={value === savedanswer}`,而非仅依赖 `radiogroup` 的 `value`。
在基于分页的多选题应用(如在线测验)中,使用 shadcn/ui 的 RadioGroup 组件时,开发者常误以为只要为 RadioGroup 设置 value 属性,其内部的 RadioGroupItem 就会自动同步选中状态。但实际并非如此——RadioGroupItem 是无状态的底层组件,它不会主动读取父级 RadioGroup 的 value 进行渲染判断。当多个题目共用相同选项文本(例如连续两题均含 “Hippo”),且 questionIndex 变更后 RadioGroup 重新挂载或重渲染时,浏览器可能因 DOM 复用或 id 冲突,沿用上一个 RadioGroupItem 的原生 checked 状态,导致「答案残留」现象。
✅ 正确做法:显式声明每个选项的 checked 状态
你需要在渲染每个 RadioGroupItem 时,显式传入 checked prop,使其严格受当前题目的已保存答案控制:
{props.questionOptions.map((answerText, i) => (
<div key={answerText} className="flex items-center space-x-2">
<RadioGroupItem
value={answerText}
// ✅ 关键修复:显式控制 checked 状态
checked={props.savedAnswers[props.questionIndex]?.answer === answerText}
disabled={props.savedAnswers[props.questionIndex]?.checked}
id={`${props.questionIndex}-${answerText}`} // ✨ 建议增强唯一性
/>
<Label htmlFor={`${props.questionIndex}-${answerText}`}>{answerText}</Label>
</div>
))}? 为什么 id 也要加题号前缀?
RadioGroupItem 依赖 id 与 <Label htmlFor> 关联。若不同题目使用相同 answerText(如都含 "Hippo"),不加题号会导致多个 input 共享同一 id,违反 HTML 规范,并可能引发浏览器自动选中逻辑混乱。添加 questionIndex 前缀可确保全局唯一性。
? 补充注意事项
- RadioGroup 的 value 仍需保留:它用于触发 onValueChange 回调及表单受控逻辑,不可移除;
- 避免 key 仅用 answerText:若选项文本重复(如多题均有 "None of the above"),应改用 i 或组合键(如 ${questionIndex}-${i})作为 key,防止 React 列表复用异常;
- 初始化 savedAnswers:建议在 useState 初始化时预设空对象或合理默认值,避免 undefined?.answer 报错;
- disabled 逻辑优化建议:当前 disabled={savedAnswers[...]?.checked} 仅禁用已提交题目的选择,符合业务逻辑;若需允许修改已答题目,可移除此 disabled 或改为条件控制。
✅ 完整受控示例片段
<RadioGroup
value={props.savedAnswers[props.questionIndex]?.answer}
onValueChange={(chosenAnswer) => {
props.saveAnswer(chosenAnswer);
}}
>
{props.questionOptions.map((answerText, i) => (
<div key={`${props.questionIndex}-${i}`} className="flex items-center space-x-2">
<RadioGroupItem
value={answerText}
checked={props.savedAnswers[props.questionIndex]?.answer === answerText}
disabled={props.savedAnswers[props.questionIndex]?.checked}
id={`${props.questionIndex}-${answerText}`}
/>
<Label htmlFor={`${props.questionIndex}-${answerText}`}>{answerText}</Label>
</div>
))}
</RadioGroup>通过以上调整,每道题的单选状态将完全解耦、精确受控,彻底杜绝跨题答案污染问题,同时保持 shadcn 组件的无障碍支持与样式一致性。










