React类组件中如何通过输入框设置多个状态值?
问题描述
操作表单输入框时控制台出现警告:
Warning: A component is changing a controlled input to be uncontrolled. This is likely caused by the value changing from a defined to undefined, which should not happen. Decide between using a controlled or uncontrolled input element for the lifetime of the component.
at input
at div
at form
at div
at App
当前代码如下:
// import GeneralInfo from "./components/GeneralInfo"; class App extends Component { constructor(){ super(); this.state = { general: { fname: "", lname: "", email: "", phn: "", location: "" } } } handleChange = (e) => { this.setState({ general: { [e.target.id]: e.target.value, } }); } onSubmitTask = (e) => { e.preventDefault(); console.log(this.state); } render() { const { general } = this.state; return ( <div> <form action="#" onSubmit={this.onSubmitTask}> <div id="name"> <input type="text" id="fname" placeholder="First Name" onChange={this.handleChange} value={general.fname}/> <input type="text" id="lname" placeholder="Last Name" onChange={this.handleChange} value={general.lname}/> </div> <div id="rest"> <input type="text" id="phn" placeholder="ph number" onChange={this.handleChange} value={general.phn}/> <input type="text" id="email" placeholder="email@example.com" onChange={this.handleChange} value={general.email}/> <input type="text" id="location" placeholder="city, state" onChange={this.handleChange} value={general.location}/> </div> <input type="submit" /> </form> </div> ); } } export default App;
问题核心:当前handleChange会直接覆盖整个general对象,导致未修改的字段变为undefined,触发受控组件转非受控的警告。要求仅用类组件实现,不为每个字段单独写修改函数,寻找最优解。
解决方法
问题根源是更新嵌套状态时未保留原general对象的其他属性。可以通过对象扩展运算符或Object.assign先复制原有属性,再覆盖当前修改的字段,既保留所有状态值,又不用单独写多个处理函数。
方法一:使用对象扩展运算符(推荐,语法简洁)
修改后的handleChange函数:
handleChange = (e) => { this.setState({ general: { ...this.state.general, // 复制原有general对象的所有属性 [e.target.id]: e.target.value // 覆盖当前输入框对应的属性 } }); }
方法二:使用Object.assign(兼容性更好,适合旧环境)
如果项目需要兼容不支持扩展运算符的环境,可改用此写法:
handleChange = (e) => { this.setState({ general: Object.assign({}, this.state.general, { [e.target.id]: e.target.value }) }); }
修改后,每次更新状态都会保留general里的所有原有字段,仅更新当前输入的属性,不会出现undefined值,警告会自动消失,同时保持了单函数处理所有输入的简洁性。
内容的提问来源于stack exchange,提问作者Faizan Ahmad

