如何在React中优雅的处理doubleClick

4,887 阅读2分钟
原文链接: segmentfault.com

背景

上午楼主遇到一个需要处理双击事件的需求,在这里介绍下如何在触发doubleCLick时间的时候, 不触发click事件的解决办法, 顺便分享给大家。

问题阐述

首先, 我们的DOM 是天然支持dbClick 事件的, 线上demo:

codepen.io/scaukk/pen.…点击预览

可以清晰的看到, 双击之后, 触发处理双击事件的逻辑, 但是同时也触发了两次click事件:

clipboard.png

这个副作用不是我们预期的, 需要处理一下。

解决办法

解决办法也很简单: 延迟 click事件的处理, 直到判断这个click 不在 doubleClick 中。

原理

这个延迟的click事件会放在一个 Promise 队列中, 并处于pending状态。

当doubleClick事件触发之后, 就取消所有的Pending Promises, 这些事件也就不会执行。

可取消的Promise

要处理这些处于 penging 状态的Promise, 我们需要用到可取消的Promise, 这个话题我在另一片文章中讨论过, 有兴趣的可以看一下。

下面是一个可以cancel的Promise的简单实现:

export const cancellablePromise = promise => {
  let isCanceled = false;

  const wrappedPromise = new Promise((resolve, reject) => {
    promise.then(
      value => (isCanceled ? reject({ isCanceled, value }) : resolve(value)),
      error => reject({ isCanceled, error }),
    );
  });

  return {
    promise: wrappedPromise,
    cancel: () => (isCanceled = true),
  };
};

要解决开头提到的这个问题, 我们就需要用到这个大杀器。

先看下最终的结果,双击一下:

clipboard.png

主要代码:

const EnhancedClickableBox = stopTriggerClicksOnDoubleClick(ClickableBox)

const DoubleClickExample = () => (
  <EnhancedClickableBox
    onClick={() => console.log("on click")}
    onDoubleClick={() => console.log("on double click")}
  />
);

const App = () => {
  return (
    <DoubleClickExample />
  )
}

ReactDOM.render(<App />, document.getElementById("app"));

线上Demo:

codepen.io/scaukk/pen.…点击预览

Hooks 版本

const ClickableBox = ({ onClick, onDoubleClick }) => {
  const [handleClick, handleDoubleClick] = useClickPreventionOnDoubleClick(onClick, onDoubleClick);

  return (
    <button onClick={handleClick} onDoubleClick={handleDoubleClick}>
      Click or double click
    </button>
  );
};


const DoubleClickExample = () => (
  <ClickableBox
    onClick={() => console.log("on click")} 
    onDoubleClick={() => console.log("on double click")}/>
);



const App = () => {
  return (
   <DoubleClickExample />
  )
}

ReactDOM.render(<App />, document.getElementById("app"));

codepen.io/scaukk/pen.…点击预览

是不是很简单, 学到了吧 XD

结语

处理双击事件的时候, 最好还是处理掉不必要的click调用, 免得产生bug.

如果文章对你有帮助, 点个赞支持一下呗。

文中若有错误,欢迎指出, 欢迎留言交流。