React JS动态表单input的onChange事件处理报错排查
问题原因
报错和受控组件警告的核心是bind传参逻辑写错了:
Function.prototype.bind()的第一个参数只负责绑定this指向,从第二个参数开始,是要提前传给目标处理函数的固定参数,这些预置参数会排在事件触发时React自动传入的event对象之前。- 你当前写的
onChange={this.handleIngredientChange.bind(this)}仅绑定了this,没有传入map遍历拿到的配料索引i。用户输入触发change事件时,React自动传入的event对象会被handleIngredientChange(i, event)当成第一个参数i接收,第二个形参event实际为undefined,访问event.target就会抛出类型错误。状态更新失败后,输入框的value属性无法和state同步,就会触发“传入value但未配置有效onChange”的受控组件警告。
修复方案
最小改动修复
只需要在bind时把索引i作为第二个参数传入即可,对应map渲染的输入框代码修改如下:
{this.state.ingredients.map((element, i) => { return ( <div key={i}> <input type='text' placeholder='new ingredient' value={element || ''} // 传入i作为预置参数,event会自动作为第二个参数传入处理函数 onChange={this.handleIngredientChange.bind(this, i)} /> {/* 你已经实现了removeClick方法,可以在这里补充删除按钮 */} <button type="button" onClick={this.removeClick.bind(this, i)}>删除配料</button> </div> ); })}
修改后输入值就能正常同步到state,报错和警告都会消失。
可选优化
你当前所有事件处理函数都在render阶段调用.bind(this),每次组件渲染都会生成新的函数引用,存在不必要的性能开销,可以选择以下两种方式优化:
- 在构造函数中提前绑定this
constructor(props) { super(props); this.state = { title: '', ingredients: [], }; // 统一绑定所有方法的this指向 this.handleTitleChange = this.handleTitleChange.bind(this); this.handleIngredientChange = this.handleIngredientChange.bind(this); this.removeClick = this.removeClick.bind(this); this.addClick = this.addClick.bind(this); this.handleSubmit = this.handleSubmit.bind(this); }
绑定后render中传参可以直接写箭头函数,比如onChange={(e) => this.handleIngredientChange(i, e)}。
2. 用类字段箭头函数定义方法,自动绑定当前组件实例的this,不需要手动调用bind:
// 箭头函数定义的方法会自动继承外层this指向 handleTitleChange = (event) => { this.setState({title: event.target.value}); } handleIngredientChange = (i, event) => { const ingredients = [...this.state.ingredients]; ingredients[i] = event.target.value; this.setState({ingredients}); } removeClick = (i) => { const ingredients = [...this.state.ingredients]; ingredients.splice(i, 1); this.setState({ingredients}); } addClick = () => { this.setState({ingredients: [...this.state.ingredients, '']}); } handleSubmit = (event) => { console.log('submit request logged') event.preventDefault(); }
另外你当前handleTitleChange的写法存在冗余,不需要先取出state里的title再覆盖,直接取输入值更新state即可。表单已经绑定了onSubmit事件,不需要再给提交按钮单独绑定onClick,重复绑定没有意义。
内容的提问来源于stack exchange,提问作者Colin Davis
相关产品推荐
相关产品推荐

