React中如何定义State/对象存储数据以调用POST API提交问卷答案
要实现这个需求,你可以按以下步骤修改代码,核心是用一个对象存储每个问题对应的选中答案ID,提交时再转换成API要求的格式:
1. 初始化存储选中答案的状态
用useState创建一个对象,键为问题ID,值为选中的答案ID,方便快速映射:
const [selectedAnswers, setSelectedAnswers] = useState({});
2. 修正单选按钮属性并添加选择事件
原代码里的单选按钮存在分组、值存储、标签关联的问题,调整后确保单选互斥、能正确捕获选中的答案ID:
{testQuestions.map((item) => { return ( <div key={item.question.id}> {/* 添加key避免React警告 */} <h2>{item.question.title_text}</h2> {item.answers.map((sub) => { return ( <div key={sub.id}> {/* 添加key */} <input type="radio" id={`answer-${sub.id}`} name={`question-${item.question.id}`} {/* 用问题ID分组,确保同一问题单选互斥 */} value={sub.id} {/* 存储答案ID,而非文本,方便后续提交 */} checked={selectedAnswers[item.question.id] === sub.id.toString()} {/* 标记当前选中状态 */} onChange={() => handleAnswerSelect(item.question.id, sub.id)} /> <label htmlFor={`answer-${sub.id}`}>{sub.title_text}</label> {/* React中用htmlFor替代for */} <br /> </div> ); })} </div> ); })}
3. 实现选择变更处理函数
这个函数负责更新选中状态,将当前问题ID和对应的答案ID绑定:
const handleAnswerSelect = (questionId, answerId) => { setSelectedAnswers(prev => ({ ...prev, [questionId]: answerId.toString() // 转字符串匹配input的value类型 })); };
4. 处理表单提交逻辑
在提交时,把selectedAnswers转换成API要求的数组格式,再发送POST请求:
const handleSubmit = async (e) => { e.preventDefault(); // 阻止表单默认跳转行为 // 转换数据为API要求的格式 const result = testQuestions.map(item => { const questionId = item.question.id; const answerId = selectedAnswers[questionId]; // 简单校验:确保每个问题都已回答 if (!answerId) { alert(`请完成问题:${item.question.title_text}`); return null; } return { questionId, answerId: parseInt(answerId), // 转数字匹配API的数值类型 metricId: item.question.metric_id, subMetricId: item.question.sub_metric_id }; }).filter(item => item !== null); // 过滤未回答的问题 // 有未回答问题时终止提交 if (result.length !== testQuestions.length) return; try { await axios.post('你的POST API地址', { result }); alert('提交成功'); // 可选:提交后重置选中状态 setSelectedAnswers({}); } catch (error) { console.error('提交失败:', error.message); alert('提交失败,请重试'); } };
最后给表单绑定提交事件:
<form className="App" onSubmit={handleSubmit}> {/* 原有表单内容 */} <button className="btn btn-default" type="submit">Submit</button> </form>
完整修改后的代码
import { useState, useEffect } from 'react'; import axios from 'axios'; const Questionnaire = () => { const [testQuestions, setTestQuestions] = useState([]); const [selectedAnswers, setSelectedAnswers] = useState({}); useEffect(() => { const fetchTestsQuestion = async () => { try { const { data } = await axios.get('你的GET API地址'); setTestQuestions(data.questions); } catch (error) { console.error(error.message); } }; fetchTestsQuestion(); }, []); const handleAnswerSelect = (questionId, answerId) => { setSelectedAnswers(prev => ({ ...prev, [questionId]: answerId.toString() })); }; const handleSubmit = async (e) => { e.preventDefault(); const result = testQuestions.map(item => { const questionId = item.question.id; const answerId = selectedAnswers[questionId]; if (!answerId) { alert(`请回答问题:${item.question.title_text}`); return null; } return { questionId, answerId: parseInt(answerId), metricId: item.question.metric_id, subMetricId: item.question.sub_metric_id }; }).filter(item => item !== null); if (result.length !== testQuestions.length) return; try { await axios.post('你的POST API地址', { result }); alert('提交成功'); setSelectedAnswers({}); } catch (error) { console.error('提交失败:', error.message); alert('提交失败,请重试'); } }; return ( <form className="App" onSubmit={handleSubmit}> {testQuestions.map((item) => { return ( <div key={item.question.id} style={{ marginBottom: '20px' }}> <h2>{item.question.title_text}</h2> {item.answers.map((sub) => { return ( <div key={sub.id} style={{ marginLeft: '10px' }}> <input type="radio" id={`answer-${sub.id}`} name={`question-${item.question.id}`} value={sub.id} checked={selectedAnswers[item.question.id] === sub.id.toString()} onChange={() => handleAnswerSelect(item.question.id, sub.id)} /> <label htmlFor={`answer-${sub.id}`}>{sub.title_text}</label> <br /> </div> ); })} </div> ); })} <button className="btn btn-default" type="submit">Submit</button> </form> ); }; export default Questionnaire;
关键说明
- 用对象存储选中状态:键值对的形式能快速定位每个问题的选中答案,更新和读取效率高
- 单选分组修正:通过
name属性绑定问题ID,确保同一问题的选项互斥 - 数据格式转换:提交时直接遍历原始问卷数据,结合选中状态生成API要求的结构,避免额外的数据处理
- 基础校验:添加未回答提示,确保提交数据的完整性
内容的提问来源于stack exchange,提问作者Ariana
相关产品推荐
相关产品推荐

