React自定义textarea组件onChange触发时event.target.value为undefined求助
问题排查及修复方案
问题根因
- 合成事件回收问题:React 合成事件对象会被放入事件池复用,setState 的回调属于异步执行场景,此时事件对象已经被回收重置,
e.target变为null,自然无法读取e.target.value。 - 事件参数不匹配:textarea 的 onChange 原生事件只会传递1个事件对象参数,你定义的
handleChange接收的第二个参数v本身不存在,值为undefined,传递给父组件后也无法正确更新状态。 - this 指向丢失:类组件的普通方法直接赋值给事件回调时,执行上下文的
this不会指向组件实例,会导致this.setState、this.props访问异常。 - 冗余受控状态:子组件内部额外维护了一份 value 状态,父组件也有独立的 comment 状态,后续容易出现父子状态不同步的问题。
修复方案
方案1:保留子组件内部状态(适配现有写法)
修复后 TextBox 组件代码
class TextBox extends React.Component { constructor(props) { super(props); this.state = { value: props.value }; } // 箭头函数自动绑定组件this指向 handleChange = (e) => { // 提前从事件对象中取出所需值,避免异步回调访问时事件被回收 const currentValue = e.target.value; console.log("输入值: ", currentValue); this.setState({ value: currentValue }, () => { // 直接传递取出的输入值给父组件回调 this.props.handleChange(currentValue); }); }; // 同步父组件传入的value更新,避免状态不一致 componentDidUpdate(prevProps) { if (prevProps.value !== this.props.value) { this.setState({ value: this.props.value }); } } render() { const { name } = this.props; const { value } = this.state; return ( <div> <h2>{name}</h2> <textarea value={value} onChange={this.handleChange} /> </div> ); } }
修复后父组件调用代码
const [comment, setComment] = useState(''); // 直接接收输入值,用函数式更新避免依赖comment,减少不必要重渲染 const handleChange = useCallback((val) => { setComment(val); }, []); // 组件调用保持不变 <TextBox name="comment" value={comment} handleChange={handleChange} />
方案2:简化为纯受控组件(更推荐,无状态冗余)
子组件不需要维护内部状态,完全由父组件控制值,实现更简洁,无状态同步问题:
class TextBox extends React.Component { handleChange = (e) => { this.props.handleChange(e.target.value); }; render() { const { name, value } = this.props; return ( <div> <h2>{name}</h2> <textarea value={value} onChange={this.handleChange} /> </div> ); } }
父组件调用代码和方案1一致即可。
内容的提问来源于stack exchange,提问作者Ron
相关产品推荐
相关产品推荐

