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
相关产品推荐
相关产品推荐

