React异步函数中e.preventDefault()报错:不是函数的问题排查
React异步点击事件中e.preventDefault()报错的问题分析与解决
问题描述
我发现传入事件的函数中未调用preventDefault(),且defaultPrevented值为false,因此需要调用e.preventDefault()。但在异步函数中调用该方法时,出现报错:
Uncaught (in promise) TypeError: e.preventDefault is not a function
相关代码片段
const steps=(props,state,handleSave) = [ { title:"Create Application" content:( <ApplicationForm initialValues={props.application} onSubmit={handleSave} /> ), buttons:[ <a onClick={async (e) => { const response = await handleSave( e, { ...props.formValues, } ); if (response){ return props.history.push({ pathname: `${routes.EDIT_APPLICATION.dynamicRoute( props.application?.application_guid)}`, state: { current: 1 }, }); } return null; }} > Save Application </a> ] export class ApplicationPage extends Component { state={ current: 0, // 原代码此处用等号为语法错误,需改为冒号 } handleSave = async(e, values) => { e.preventDefault(); // 此处报错:e.preventDefault is not a function const applicationFound = Boolean(values.application_guid); if (!applicationFound){ return this.handleCreateApplication(values); } return this.handleUpdateApplication(values); };
事件对象属性详情
e: Class altKey: false bubbles: true button: 0 buttons: 0 cancelable: true clientX: 680 clientY: 241 ctrlKey: false currentTarget: a defaultPrevented: false detail: 1 dispatchConfig: {phasedRegistrationNames: {…}, dependencies: Array(1), eventPriority: 0} eventPhase: 3 getModifierState: ƒ modifierStateGetter(keyArg) isDefaultPrevented: ƒ functionThatReturnsFalse() length: 0 name: "functionThatReturnsFalse" prototype: {constructor: ƒ} arguments: (...) caller: (...) [[FunctionLocation]]: react-dom.development.js?7f13:8352 [[Prototype]]: ƒ () [[Scopes]]: Scopes[3] isPropagationStopped: ƒ functionThatReturnsFalse() isTrusted: true metaKey: false movementX: 0 movementY: 0 nativeEvent: PointerEvent {isTrusted: true, pointerId: 1, width: 1, height: 1, pressure: 0, …} pageX: 680 pageY: 241 relatedTarget: null screenX: -1368 screenY: 198 shiftKey: false target: a timeStamp: 1155255.8999999985 type: "click" view: Window {window: Window, self: Window, document: document, name: '', location: Location, …} _dispatchInstances: FiberNode {tag: 5, key: null, elementType: 'a', type: 'a', stateNode: a, …} _dispatchListeners: ƒ (_x) _targetInst: FiberNode {tag: 5, key: null, elementType: 'a', type: 'a', stateNode: a, …} [[Prototype]]: Class
问题原因
核心原因是React的合成事件对象采用池化复用机制:当同步代码执行完毕后,React会自动回收合成事件对象,重置其所有属性和方法。在你的代码中,onClick是异步回调,await handleSave(...)会等待异步操作完成,此时React已经回收了原事件对象e,所以在handleSave中调用e.preventDefault()时,该方法已经不存在,从而触发报错。
从事件对象属性里的isDefaultPrevented: ƒ functionThatReturnsFalse()也能看出,事件对象已经被重置,原本的方法已失效。
解决方案
提供两种可行的解决办法:
1. 提前调用preventDefault()(推荐)
在onClick的同步代码阶段就调用e.preventDefault(),避免等到异步操作后事件对象被回收:
onClick={async (e) => { e.preventDefault(); // 提前调用,此时事件对象未被回收 const response = await handleSave( { ...props.formValues } ); if (response){ return props.history.push({ pathname: `${routes.EDIT_APPLICATION.dynamicRoute( props.application?.application_guid)}`, state: { current: 1 }, }); } return null; }}
同时修改handleSave,移除不必要的事件参数:
handleSave = async(values) => { const applicationFound = Boolean(values.application_guid); if (!applicationFound){ return this.handleCreateApplication(values); } return this.handleUpdateApplication(values); };
2. 使用e.persist()保留事件对象
如果必须在异步逻辑中使用事件对象,可以调用e.persist()阻止React回收事件对象:
onClick={async (e) => { e.persist(); // 阻止事件对象被池化回收 const response = await handleSave( e, { ...props.formValues } ); // 后续逻辑... }}
这种方式会让事件对象不进入池化,增加内存开销,不建议在高频触发的事件中使用。
另外注意:原代码中state的定义有语法错误,current=0应改为current: 0。
内容的提问来源于stack exchange,提问作者JarochoEngineer
相关产品推荐
相关产品推荐

