react SyntheticEvent 合成事件机制
在弄懂react SyntheticEvent 之前我遇到了一个问题,这个问题一直困扰我很久,知道我看了这篇博客之后,参考了react 文档,总算弄的大致明白。
首先看一下我的问题。
当我需要在一个点击事件中应用debounce函数(防抖函数)在防止点击事件的多次误触情况是我的第一反应是这样的
options.map(item => {
let option = (
<li
className="uy-menu-item"
key={item.fieldName}
data-name={item.fieldName}
data-type={item.type}
onClick={_.debounce(this.handleClick, 200)}
>
{item.displayName}
</li>
);
if (item.type === "DIMENSION") {
demension.push(option);
} else {
mersure.push(option);
}
});
handleClick(e) {
let { seriesIndex } = this.state;
let key = e.target.getAttribute("data-name”);
...
}
这个时候浏览器会报出异常:TypeError: Cannot read property 'getAttribute' of null
检查event对象可以看到target 为null,但是用了debounce 函数之后会出现获取不到event.target的情况呢?接下来需要介绍下react 的合成事件机制。
合成事件(SyntheticEvent)
事件处理程序通过 合成事件(SyntheticEvent)的实例传递,SyntheticEvent 是浏览器原生事件跨浏览器的封装。SyntheticEvent 和浏览器原生事件一样有 stopPropagation()、preventDefault() 接口,而且这些接口夸浏览器兼容。 如果由于某种原因发现您需要基础浏览器事件,只需使用该nativeEvent属性即可获取它。每个SyntheticEvent对象都具有以下属性:
boolean bubbles
boolean cancelable
DOMEventTarget currentTarget
boolean defaultPrevented
number eventPhase
boolean isTrusted
DOMEvent nativeEvent // 原生事件对象
void preventDefault()
boolean isDefaultPrevented()
void stopPropagation()
boolean isPropagationStopped()
DOMEventTarget target
number timeStamp
string type
事件池
将SyntheticEvent被合并。这意味着SyntheticEvent在调用事件回调之后,将重用该对象并且所有属性都将无效。这是出于性能原因。因此,您无法以异步方式访问事件。
function onClick(event) {
console.log(event); // => nullified object.
console.log(event.type); // => "click"
const eventType = event.type; // => "click"
setTimeout(function() {
console.log(event.type); // => null
console.log(eventType); // => "click"
}, 0);
// Won't work. this.state.clickEvent will only contain null values.
this.setState({clickEvent: event});
// You can still export event properties.
this.setState({eventType: event.type});
}
注意:如果要以异步方式访问事件属性,则应调用event.persist(),该方法将从池中删除合成事件,并允许用户代码保留对事件的引用。 可以看到react 文档的注意这里给我我们解决办法,因为我们在使用debounce函数时,其内部实际上是使用setTimeout异步调用回调函数,所以直接在debounce函数内部获取外部的event对象是不能直接拿到的,这时调用event.persist()就可以拿到事件的引用。
参考:
在 react 组件中使用 debounce 函数(http://billqiu.github.io/2017/10/15/how-to-debounce-in-react/)
SyntheticEvent(https://reactjs.org/docs/events.html?)