React函数组件动态表单受控组件警告无类解决方案
函数组件完全可以解决这个问题,不需要使用类组件。
问题原因
你碰到的非受控组件警告核心来自两个问题:
- 新增表单项时字段名拼写错误:初始表单项的描述字段为
StepDisc,但addFields方法里新增的对象误写为StepDiscs(末尾多了个s),导致新加表单项的StepDisc属性值为undefined。React中如果input的value属性初始为undefined,会默认将组件识别为非受控组件,后续赋值时组件切换为受控状态,就会抛出对应警告。 - 原代码状态更新时只浅拷贝了外层数组,直接修改了数组内部的原对象,不符合React状态不可变的要求,极端场景下会出现渲染不生效的问题。
修复后完整代码
import { useState } from 'react'; function DynamicForm() { const [formFields, setFormFields] = useState([ { StepNo: '', StepDisc: '' }, ]) const handleFormChange = (event, index) => { const { name, value } = event.target; setFormFields(prev => prev.map((item, i) => { if (i === index) return { ...item, [name]: value } return item })) } const submit = (e) => { e.preventDefault(); console.log(formFields) } const addFields = () => { // 修正字段名拼写,和初始字段保持一致 const newField = { StepNo: '', StepDisc: '' } setFormFields(prev => [...prev, newField]) } const removeFields = (removeIndex) => { setFormFields(prev => prev.filter((_, index) => index !== removeIndex)) } return ( <div className=""> <form onSubmit={submit}> {formFields.map((form, index) => { return ( <div key={index}> <input name='StepNo' placeholder='StepNo' onChange={event => handleFormChange(event, index)} value={form.StepNo} /> <input name='StepDisc' placeholder='StepDisc' onChange={event => handleFormChange(event, index)} value={form.StepDisc} /> <button type="button" onClick={() => removeFields(index)}>Remove</button> </div> ) })} </form> <button type="button" onClick={addFields}>Add More..</button> <br /> <button type="submit">Submit</button> </div> ); } export default DynamicForm;
关键修复点说明
- 修正了
addFields中的字段拼写错误,保证所有表单项对象都完整包含StepNo和StepDisc字段,初始值为空字符串,从根源避免value为undefined导致的受控/非受控切换问题 - 所有状态更新都遵循不可变原则:更新输入值、新增/删除字段时都不直接修改原状态,而是生成全新的状态值传递给更新方法,避免潜在渲染异常
- 所有非提交按钮添加
type="button"属性,避免表单内按钮默认触发表单提交的问题 - 状态更新改用函数式写法,避免连续操作状态时拿到过期的状态快照
- 额外兜底方案:如果后续业务存在动态增减字段、无法保证所有字段初始都存在的场景,可以给input的value加空值兜底,例如写成
value={form.StepDisc ?? ''},就算对应字段未定义,value也始终为字符串类型,彻底杜绝这类非受控组件警告。 - 补充优化:如果表单增删操作比较频繁,不建议用数组下标作为map渲染的key,可以给每个新增字段生成唯一id作为key,避免重渲染时的输入值错位问题。
内容的提问来源于stack exchange,提问作者risky last
相关产品推荐
相关产品推荐

