You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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的渲染警告,需要补充。

修复代码

  1. 使用对象计算属性名(用方括号包裹question),动态引用当前问题作为属性键
  2. 给循环的外层容器添加唯一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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 12:44:55