React中Input绑定内联箭头函数触发onChange报Cannot read property 'value' of null错误原因
为什么React类组件内联onChange会抛出"Cannot read property 'value' of null"错误?
这个问题其实是React合成事件的事件池机制在搞鬼,我来给你拆解清楚整个逻辑:
先看你出问题的内联代码
<input type='text' placeholder='title' value={this.state.title} onChange={(e) => this.setState(() => ({title: e.target.value}))} required autoFocus />
这里的关键问题在于:setState的函数式更新回调是异步执行的,而React为了性能优化,会在事件处理函数执行完毕后,把合成事件对象放回事件池,同时将对象的所有属性置为null。当setState的回调触发时,你再去访问e.target.value,此时的e已经是被回收的空对象了,自然会抛出"Cannot read property 'value' of null"的错误。
再看你正常运行的独立函数写法
onTitleChange = (e) => { const title = e.target.value; // 同步阶段就提取并保存值 this.setState(() => ({title})); };
这里你在事件处理函数的同步执行阶段,就把e.target.value的具体值提取到了变量title中。哪怕之后事件对象被React回收,变量里已经保存了独立的字符串值,setState的回调再访问这个变量时完全不受影响,所以代码能正常运行。
额外的几种解决方案
除了抽成独立函数,你还可以用这几种方式修复内联写法的问题:
- 方案一:提前保存值(和独立函数的核心逻辑一致)
onChange={(e) => { const title = e.target.value; this.setState(() => ({title})); }}
- 方案二:保留事件对象
调用e.persist()可以让React跳过回收这个合成事件对象,这样异步回调里也能正常访问它的属性:
onChange={(e) => { e.persist(); this.setState(() => ({title: e.target.value})); }}
- 方案三:直接传对象给setState
如果你的状态更新不需要依赖之前的state值(就像这个场景),完全可以不用函数式更新,直接传对象:
onChange={(e) => this.setState({title: e.target.value})}
内容的提问来源于stack exchange,提问作者ahrooran
相关产品推荐
相关产品推荐

