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

MaterialUI动态渲染组件时value prop未随useState状态变更更新问题

问题根因

  • 第一个致命错误是你把JSX元素存在了answers状态里:这些JSX创建时绑定的是创建瞬间的values状态快照,后续values更新不会触发这些已经生成的JSX更新props,所以TextField的value永远停留在初始值。
  • 第二个错误是状态更新逻辑不规范:handleAnswersChange中直接修改了原状态的引用,且输入值赋值逻辑错误,会导致输入内容重复叠加。
  • 第三个错误是动态新增答案的逻辑颠倒:你应该先更新values.answers的数据源,再由数据源驱动组件渲染,而非先生成组件存到状态里。

修复方案

首先直接删掉存JSX的const [answers, setAnswers] = React.useState<Array<JSX.Element>>([])这行,所有答案组件直接通过遍历values.answers渲染即可。
然后修正handleAnswersChange的逻辑,再修正新增答案的逻辑。

修正后的完整代码

interface State {
  title: string;
  question: string;
  answers: Array<Answer>;
  correctAnswer: number;
}

interface Answer {
  answer: string;
  id: number;
}

export default function CreateQuestion() {
  const [errorAnswer, setErrorAnswer] = React.useState(false);
  const [values, setValues] = React.useState<State>({
    title: "",
    question: "",
    answers: [{ answer: "", id: 1 }],
    correctAnswer: 1,
  });

  useEffect(() => {
    console.log(values);
  }, [values]);

  const handleChange =
    (prop: keyof State) => (event: React.ChangeEvent<HTMLInputElement>) => {
      setValues({ ...values, [prop]: event.target.value });
    };

  const handleAnswersChange = (id: number) => 
    (event: React.ChangeEvent<HTMLInputElement>) => {
      setValues(prev => {
        const newAnswers = prev.answers.map(answer => {
          if (answer.id === id) {
            return { ...answer, answer: event.target.value };
          }
          return answer;
        });
        return { ...prev, answers: newAnswers };
      });
  };

  const createAnswer = () => {
    setValues(prev => {
      const newId = prev.answers.length + 1;
      return {
        ...prev,
        answers: [...prev.answers, { answer: "", id: newId }]
      };
    });
  };

  // 直接在渲染处遍历生成答案组件,不要存在state里
  return (
    <div>
      {/* 其他表单字段省略 */}
      {values.answers.map((answer, index) => (
        <Box sx={{ m: 1 }} key={answer.id}>
          <FormControl
            sx={{ width: "60ch" }}
            variant="outlined"
          >
            <TextField
              id={`answer-${answer.id}`}
              label={`Answer ${index + 1}`}
              value={answer.answer}
              onChange={handleAnswersChange(answer.id)}
            />
          </FormControl>
        </Box>
      ))}
      {/* 新增答案按钮 */}
      <button onClick={createAnswer}>新增答案</button>
    </div>
  )
}

关键修改说明

  • 移除了存储JSX的状态,改为由values.answers数据源直接驱动组件渲染,每次状态更新都会重新生成组件,绑定最新的value
  • handleAnswersChange采用函数式更新写法,直接基于上一次的状态计算新值,避免状态闭包问题
  • 输入值直接取event.target.value,不再做不必要的拼接
  • 新增答案时先更新数据源,自动触发新的组件渲染,不需要手动构造JSX存入状态

内容的提问来源于stack exchange,提问作者Vavom

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 18:27:03