天天看點

如何在React中優雅的處理doubleClick背景問題闡述解決辦法原理可取消的Promise結語

背景

上午樓主遇到一個需要

處理輕按兩下事件

的需求,在這裡介紹下

如何在觸發doubleCLick時間的時候, 不觸發click事件

的解決辦法, 順便分享給大家。

問題闡述

首先, 我們的DOM 是天然支援dbClick 事件的, 線上demo:

https://codepen.io/scaukk/pen/BaBoYeO

可以清晰的看到, 輕按兩下之後, 觸發處理輕按兩下事件的邏輯, 但是同時也觸發了兩次click事件:

如何在React中優雅的處理doubleClick背景問題闡述解決辦法原理可取消的Promise結語

這個副作用不是我們預期的, 需要處理一下。

解決辦法

解決辦法也很簡單:

延遲 click事件的處理, 直到判斷這個click 不在 doubleClick 中。

原理

這個延遲的click事件會放在一個

Promise 隊列

中, 并處于

pending

狀态。

當doubleClick事件觸發之後, 就取消所有的Pending Promises, 這些事件也就不會執行。

可取消的Promise

要處理這些處于 penging 狀态的Promise, 我們需要用到可取消的Promise, 這個話題我在另一篇文章中讨論過, 有興趣的可以看一下:

https://segmentfault.com/a/1190000019456742

下面是一個可以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),
  };
};
           

複制

要解決開頭提到的這個問題, 我們就需要用到這個大殺器。

先看下最終的結果,輕按兩下一下:

如何在React中優雅的處理doubleClick背景問題闡述解決辦法原理可取消的Promise結語

主要代碼:

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:

https://codepen.io/scaukk/pen/yLBYojv

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"));
           

複制

https://codepen.io/scaukk/pen/OJLyrOM

是不是很簡單~

結語

處理輕按兩下事件的時候, 最好還是處理掉不必要的click調用, 免得産生bug.

文中若有錯誤,歡迎指出, 歡迎留言交流。