React问卷应用迭代JSON渲染表单报错及答案追踪问题求助
问题解决与代码修正
1. 修复"question.map is not a function"错误
- 错误原因:你尝试对单个
question对象调用map()方法,但question是对象而非数组,应该遍历的是question.answerOptions数组。 - 额外处理:第四个问题没有
answerOptions属性,需要通过可选链?.判断存在性,同时只在answerType为radio时渲染选项模块。
2. 用useState追踪所有问题的答案
- 初始化一个对象类型的state,以问题索引为键存储对应答案。
- 给每个输入控件绑定
onChange事件,更新state中对应问题的答案值。
修正后的完整代码
import React, { useState } from "react"; import "./survey.css"; const MapSurvey = () => { const questions = [ { questionText: "First Q", answerOptions: [ { answerText: "One", value: 1 }, { answerText: "Two", value: 2 }, { answerText: "Three", value: 3 }, { answerText: "Four", value: 4 }, { answerText: "Five", value: 5 }, ], answerType: "radio", }, { questionText: "Second", answerOptions: [ { answerText: "One", value: 1 }, { answerText: "Two", value: 2 }, { answerText: "Three", value: 3 }, { answerText: "Four", value: 4 }, ], answerType: "radio", }, { questionText: "Third", answerOptions: [ { answerText: "One", value: 1 }, { answerText: "Two", value: 2 }, { answerText: "Three", value: 3 }, { answerText: "Four", value: 4 }, { answerText: "Five", value: 5 }, ], answerType: "radio", }, { questionText: "FirstInput", answerType: "text", }, ]; // 存储所有问题的答案,键为问题索引,值为对应答案 const [answers, setAnswers] = useState({}); // 更新对应问题的答案 const handleAnswerChange = (questionIndex, value) => { setAnswers(prev => ({ ...prev, [questionIndex]: value })); }; // 处理表单提交逻辑 const handleSubmit = (e) => { e.preventDefault(); // 可替换为发送到后端或其他业务逻辑 console.log("提交的答案:", answers); }; return ( <div className="w-full py-[2rem] px-4 bg-white"> <div className="mx-auto text-center flex flex-col"> <form onSubmit={handleSubmit}> {questions.map((question, questionIndex) => ( <div key={questionIndex} className="flex flex-col p-4 my-4"> <h2>{question.questionText}</h2> {/* 渲染单选框类型问题 */} {question.answerType === "radio" && question.answerOptions?.map((opt, optIndex) => ( <div key={optIndex} className="radio mt-3 mb-3"> <input name={`question-${questionIndex}`} type="radio" id={`option-${questionIndex}-${optIndex}`} hidden="hidden" value={opt.value} checked={answers[questionIndex] === opt.value} onChange={() => handleAnswerChange(questionIndex, opt.value)} /> <label htmlFor={`option-${questionIndex}-${optIndex}`} className="px-2 py-1 rounded-lg flex justify-left items-center font-medium text-black checked:text-white w-full sm:w-6/12 h-10" > {opt.answerText} </label> </div> ))} {/* 渲染文本输入框类型问题 */} {question.answerType === "text" && ( <input type="text" className="mt-3 px-2 py-1 rounded-lg border" value={answers[questionIndex] || ""} onChange={(e) => handleAnswerChange(questionIndex, e.target.value)} placeholder="请输入答案" /> )} </div> ))} <button type="submit" className="mt-4 px-4 py-2 bg-blue-500 text-white rounded">Submit</button> </form> </div> </div> ); }; export default MapSurvey;
关键修改说明
- 给列表项添加
key属性,符合React列表渲染规范 - 单选框
name设置为question-${questionIndex},确保同一问题的选项互斥 - 选项
id和label的htmlFor设置为唯一值,避免标签关联冲突 - 单选框添加
checked属性,同步选中状态与state值 - 文本输入框实现受控组件,绑定value和onChange事件
- 添加表单提交逻辑,可扩展为后端交互
内容的提问来源于stack exchange,提问作者Pisa Ponente
相关产品推荐
相关产品推荐

