为何event.currentTarget有时返回null?React按钮点击场景排查
问题与解决方案解析
问题背景
我在按钮中嵌套SVG图标组件,每个按钮绑定onClick处理器,试图通过事件对象获取按钮的name属性来更新状态。但遇到偶发现象:
event.currentTarget有时会返回null- 正常情况
console.log输出空按钮标签,失效时输出带SVG子元素的按钮,但两种场景下event.currentTarget.name都能即时正确打印,只是后续访问currentTarget时变为null - 已找到修复方式:提前把
event.currentTarget.name存入常量即可解决,但不清楚原理
核心原因:React事件池的复用机制
React为了优化性能,会维护一个事件对象池:
- 事件触发时,React从池中取出一个事件对象,填充好属性(比如
currentTarget、target等)传给事件处理函数 - 当事件处理函数执行完毕后,React会立即清空这个事件对象的所有属性(包括
currentTarget),并把它放回事件池,供后续事件复用
你的原代码中,raiseState(() => event.currentTarget.name)是把一个回调函数传给状态更新方法,这个回调是异步执行的(React会批量处理状态更新,回调会在事件处理函数完全执行完之后才触发)。等到这个回调执行时,事件对象已经被React回收清空,currentTarget自然变成了null。
而提前把event.currentTarget.name存入常量,相当于在事件对象被回收前,就把name的值提取并保存到了独立变量中,后续异步回调访问的是这个保存的常量,不受事件池回收的影响。
另外你看到console.log即时输出event.currentTarget.name正常,是因为这行代码是同步执行的,此时事件对象还没被回收,属性都处于可用状态。
可靠获取按钮name属性的几种方案
1. 提前存储属性值(你用到的方案)
在事件对象被回收前,把需要的属性值提取出来:
function changeModeHandler(event) { const name = event.currentTarget.name; console.log(event.currentTarget, name); raiseState(() => name); }
2. 直接传递name参数(更直观)
不用依赖事件对象,绑定事件时直接把按钮的name作为参数传入处理器:
function changeModeHandler(name) { raiseState(() => name); } return ( <> <button onClick={() => changeModeHandler("explain")} className="" type="button" name="explain" > <BookOpenIcon className="mode-icon" /> </button> <button onClick={() => changeModeHandler("summary")} className="" type="button" name="summary" > <KeyIcon className="mode-icon" /> </button> <button onClick={() => changeModeHandler("example")} className="" type="button" name="example" > <ListBulletIcon className="mode-icon" /> </button> </>
3. 用event.target向上查找按钮(不推荐)
如果一定要基于事件对象,可通过closest方法从触发事件的子元素向上找到父按钮,但这种方法在按钮嵌套多层元素时容易出问题:
function changeModeHandler(event) { const button = event.target.closest('button'); const name = button?.name; raiseState(() => name); }
内容的提问来源于stack exchange,提问作者rolias4031
相关产品推荐
相关产品推荐

