React动态多问题表单:State存储用户输入及输入无效问题排查
问题:React表单文本框无法输入,输入始终为空
我正在开发一个表单,需要将每个文本框的用户输入存储至React State中。表单的问题来源于外部数据源,因此我将问题与答案以键值对的形式存储在一个对象内。但当前实现存在问题:无论在文本框中输入什么内容,输入框始终保持为空,无法正常输入。
import Box from "@mui/system/Box"; import Stack from "@mui/system/Stack"; import ArrowBackIcon from "@mui/icons-material/ArrowBack"; import TextField from "@mui/material/TextField"; import { useState } from "react"; import HRMButton from "../Button/HRMButton"; import { fonts } from "../../Styles"; export default function OnboardingSurvey({prev, next, style}) { //The form could contain any number of questions not just the four used in this example const [form, setForm] = useState({ "What suggestions do you have for improving the company culture or work environment?": "", "Do you have any feedback on your manager or team that you'd like to share?": "", "How was your experience working here?": "", "Is there anything else you would like to share that we haven't discussed?": "" }); return ( <Box sx={{...{ border: "1px solid #EBEBEB", borderRadius: "10px", minWidth: "1003px", paddingX: "113px", paddingY: "63px", fontFamily: fonts.fontFamily }, ...style}}> <h4 style={{textAlign: "center", marginTop: 0}}>Please answer the questions below as detailed as possible</h4> <p style={{textAlign: "center", marginBottom: "50px"}}> Your answers are going to be used to further improve our process. </p> {Object.keys(form).map((question) => ( <> <p style={{textAlign: "left"}}>{question}</p> <TextField id={`${question}-textfield`} value={form[question]} placeholder="Your answer here" onChange={(e) => { setForm({ ...form, question: e.target.value }); }} rows={4} multiline sx={{ marginBottom: "50px", width: "100%" }} /> </> ))} <Stack direction="row" alignContent="center" justifyContent="space-between"> <HRMButton mode="secondaryB" startIcon={<ArrowBackIcon />} onClick={prev}>Previous</HRMButton> <HRMButton mode="primary" onClick={next}>Save and next</HRMButton> </Stack> </Box> ); };
解决方案
核心问题分析
问题出在onChange事件的状态更新逻辑中:你使用question: e.target.value时,question是字面量属性名,而非循环中当前的问题变量。这会导致每次输入时,你都在给对象添加一个名为question的新属性,而非更新对应问题的答案,因此文本框的value始终保持初始空字符串,看起来无法输入。
同时,循环渲染的元素缺少唯一key属性,会触发React的渲染警告,需要补充。
修复代码
- 使用对象计算属性名(用方括号包裹
question),动态引用当前问题作为属性键 - 给循环的外层容器添加唯一
key属性
{Object.keys(form).map((question) => ( <div key={question}> <p style={{textAlign: "left"}}>{question}</p> <TextField id={`${question}-textfield`} value={form[question]} placeholder="Your answer here" onChange={(e) => { setForm({ ...form, [question]: e.target.value // 用方括号包裹question,实现动态属性赋值 }); }} rows={4} multiline sx={{ marginBottom: "50px", width: "100%" }} /> </div> ))}
完整修复后的代码
import Box from "@mui/system/Box"; import Stack from "@mui/system/Stack"; import ArrowBackIcon from "@mui/icons-material/ArrowBack"; import TextField from "@mui/material/TextField"; import { useState } from "react"; import HRMButton from "../Button/HRMButton"; import { fonts } from "../../Styles"; export default function OnboardingSurvey({prev, next, style}) { //The form could contain any number of questions not just the four used in this example const [form, setForm] = useState({ "What suggestions do you have for improving the company culture or work environment?": "", "Do you have any feedback on your manager or team that you'd like to share?": "", "How was your experience working here?": "", "Is there anything else you would like to share that we haven't discussed?": "" }); return ( <Box sx={{...{ border: "1px solid #EBEBEB", borderRadius: "10px", minWidth: "1003px", paddingX: "113px", paddingY: "63px", fontFamily: fonts.fontFamily }, ...style}}> <h4 style={{textAlign: "center", marginTop: 0}}>Please answer the questions below as detailed as possible</h4> <p style={{textAlign: "center", marginBottom: "50px"}}> Your answers are going to be used to further improve our process. </p> {Object.keys(form).map((question) => ( <div key={question}> <p style={{textAlign: "left"}}>{question}</p> <TextField id={`${question}-textfield`} value={form[question]} placeholder="Your answer here" onChange={(e) => { setForm({ ...form, [question]: e.target.value }); }} rows={4} multiline sx={{ marginBottom: "50px", width: "100%" }} /> </div> ))} <Stack direction="row" alignContent="center" justifyContent="space-between"> <HRMButton mode="secondaryB" startIcon={<ArrowBackIcon />} onClick={prev}>Previous</HRMButton> <HRMButton mode="primary" onClick={next}>Save and next</HRMButton> </Stack> </Box> ); };
内容的提问来源于stack exchange,提问作者Gabriel Chan
相关产品推荐
相关产品推荐

