React中两种setState写法的差异及evt.target为null报错原因
两个handleOnChange函数的区别及报错原因解析
嘿,这个问题问得很到位!我来帮你拆解清楚这两个点:
一、两个handleOnChange的核心区别
这两个写法本质是React中setState的两种更新方式:
1. 函数式更新(回调版本)
handleOnChange(evt) { this.setState(() => ({ tickerName: evt.target.value })); }
这里给setState传入了一个回调函数,这个函数会接收prevState(更新前的state)和props作为参数,返回新的state对象。它的适用场景是新state依赖于旧state的值,比如累加计数:
this.setState(prevState => ({ count: prevState.count + 1 }))
2. 对象式更新(直接传对象版本)
handleOnChange(evt) { this.setState({ tickerName: evt.target.value }); }
这种写法直接给setState传入一个新的state对象,React会自动把这个对象和当前的state合并。它适合不需要依赖旧state的简单更新场景,就像这里直接把输入框的值赋值给tickerName。
二、为什么回调版本会抛出TypeError: evt.target is null?
这要从React的合成事件池化机制说起:
React为了优化性能,会对合成事件(SyntheticEvent,也就是你拿到的evt对象)进行复用——当事件处理函数执行完毕后,React会把这个事件对象的所有属性置为null,然后放回事件池供后续事件复用。
- 对于对象式更新:你是同步获取了
evt.target.value的值,在React回收事件对象之前,就已经把值提取出来并传入setState了,所以不会有问题。 - 对于函数式更新:
setState的回调函数是异步执行的(React可能会批量处理state更新以提升性能),当回调执行的时候,原来的evt对象已经被React回收,它的target属性已经变成null,自然就会报错。
解决办法
有两种常见的解决方式:
- 提前保存事件值:在调用
setState之前,先把evt.target.value存到变量里,这样后续回调用的是普通变量,不受事件池影响:
handleOnChange(evt) { const inputValue = evt.target.value; this.setState(() => ({ tickerName: inputValue })); }
- 阻止事件对象被回收:调用
evt.persist()方法,让React不再把这个事件对象放回池化,这样它的属性就不会被置为null:
handleOnChange(evt) { evt.persist(); this.setState(() => ({ tickerName: evt.target.value })); }
内容的提问来源于stack exchange,提问作者Paolo Guerra
相关产品推荐
相关产品推荐

