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?)

 

 
 
 
 
 
 
 
posted @ 2019-02-25 17:14  半夜盗贼  阅读(3183)  评论(0编辑  收藏  举报