React中使用useEffect后单选按钮无法取消选中的问题
问题分析与解决
核心问题
- 单选框选中状态判断逻辑错误:当前
checked属性的写法是只要selectedAnswer不为null就给选项加checked,这不符合单选框的选中逻辑——单选框应该是当前选项的value等于selectedAnswer时才标记为选中。 - useEffect依赖错误:依赖写了
setNum,但setNum是React内置的状态更新函数,不会变化,导致后续num更新时useEffect触发异常,应该监听num的变化。 - 第四个选项的value值写错:第四个
Form.Check的value用了questionsJSON.questions[num].answers[0],应该是answers[3],否则会和第一个选项value重复,导致选中状态混乱。
修正后的代码
状态与逻辑部分
const [selectedAnswer, setSelectedAnswer] = useState(""); const [num, setNum] = useState(0); const randomNumberInRange = (max) => { return Math.floor(Math.random() * (max + 1)); }; const onClickPassRadio = (e) => { e.preventDefault(); setNum(randomNumberInRange(10)); }; useEffect(() => { setSelectedAnswer(""); // 和初始状态保持一致,用空字符串而非null }, [num]); // 监听num的变化,而非setNum
表单部分
<Form> <ListGroup> <ListGroup.Item className="text-start"> <div> <Form.Check type="radio" id="0" name="answer" label={questionsJSON.questions[num].answers[0]} value={questionsJSON.questions[num].answers[0]} onChange={e => setSelectedAnswer(e.target.value)} checked={selectedAnswer === questionsJSON.questions[num].answers[0]} /> </div> </ListGroup.Item> <ListGroup.Item className="text-start"> <Form.Check type="radio" id="1" name="answer" label={questionsJSON.questions[num].answers[1]} value={questionsJSON.questions[num].answers[1]} onChange={e => setSelectedAnswer(e.target.value)} checked={selectedAnswer === questionsJSON.questions[num].answers[1]} /> </ListGroup.Item> <ListGroup.Item className="text-start"> <Form.Check type="radio" id="2" name="answer" label={questionsJSON.questions[num].answers[2]} value={questionsJSON.questions[num].answers[2]} onChange={e => setSelectedAnswer(e.target.value)} checked={selectedAnswer === questionsJSON.questions[num].answers[2]} /> </ListGroup.Item> <ListGroup.Item className="text-start"> <Form.Check type="radio" id="3" name="answer" label={questionsJSON.questions[num].answers[3]} value={questionsJSON.questions[num].answers[3]} {/* 修正此处value */} onChange={e => setSelectedAnswer(e.target.value)} checked={selectedAnswer === questionsJSON.questions[num].answers[3]} /> </ListGroup.Item> </ListGroup> <br /> <Button variant="danger" onClick={onClickPassRadio}>submit</Button> </Form>
额外优化建议
可以通过循环渲染选项减少冗余代码,适配任意数量的选项:
<Form> <ListGroup> {questionsJSON.questions[num].answers.map((answer, index) => ( <ListGroup.Item key={index} className="text-start"> <Form.Check type="radio" id={String(index)} name="answer" label={answer} value={answer} onChange={e => setSelectedAnswer(e.target.value)} checked={selectedAnswer === answer} /> </ListGroup.Item> ))} </ListGroup> <br /> <Button variant="danger" onClick={onClickPassRadio}>submit</Button> </Form>
内容的提问来源于stack exchange,提问作者Keshav
相关产品推荐
相关产品推荐

