I've created a codesandbox with a hook to handle long press and click. Basically, on mouse down, touch start events, a timer is created with setTimeout
. When the provided time elapses, it triggers long press.
On mouse up, mouse leave, touchend, etc, the timer is cleared.
useLongPress.js
import { useCallback, useRef, useState } from "react";
const useLongPress = (
onLongPress,
onClick,
{ shouldPreventDefault = true, delay = 300 } = {}
) => {
const [longPressTriggered, setLongPressTriggered] = useState(false);
const timeout = useRef();
const target = useRef();
const start = useCallback(
event => {
if (shouldPreventDefault && event.target) {
event.target.addEventListener("touchend", preventDefault, {
passive: false
});
target.current = event.target;
}
timeout.current = setTimeout(() => {
onLongPress(event);
setLongPressTriggered(true);
}, delay);
},
[onLongPress, delay, shouldPreventDefault]
);
const clear = useCallback(
(event, shouldTriggerClick = true) => {
timeout.current && clearTimeout(timeout.current);
shouldTriggerClick && !longPressTriggered && onClick();
setLongPressTriggered(false);
if (shouldPreventDefault && target.current) {
target.current.removeEventListener("touchend", preventDefault);
}
},
[shouldPreventDefault, onClick, longPressTriggered]
);
return {
onMouseDown: e => start(e),
onTouchStart: e => start(e),
onMouseUp: e => clear(e),
onMouseLeave: e => clear(e, false),
onTouchEnd: e => clear(e)
};
};
const isTouchEvent = event => {
return "touches" in event;
};
const preventDefault = event => {
if (!isTouchEvent(event)) return;
if (event.touches.length < 2 && event.preventDefault) {
event.preventDefault();
}
};
export default useLongPress;
To use the hook,
App.js
import useLongPress from "./useLongPress";
export default function App() {
const onLongPress = () => {
console.log('longpress is triggered');
};
const onClick = () => {
console.log('click is triggered')
}
const defaultOptions = {
shouldPreventDefault: true,
delay: 500,
};
const longPressEvent = useLongPress(onLongPress, onClick, defaultOptions);
return (
<div className="App">
<button {...longPressEvent}>use Loooong Press</button>
</div>
);
}
Older answer for class components:
You can use MouseDown, MouseUp, TouchStart, TouchEnd events to control timers that can act as a long press event. Check out the code below
class App extends Component {
constructor() {
super()
this.handleButtonPress = this.handleButtonPress.bind(this)
this.handleButtonRelease = this.handleButtonRelease.bind(this)
}
handleButtonPress () {
this.buttonPressTimer = setTimeout(() => alert('long press activated'), 1500);
}
handleButtonRelease () {
clearTimeout(this.buttonPressTimer);
}
render() {
return (
<div
onTouchStart={this.handleButtonPress}
onTouchEnd={this.handleButtonRelease}
onMouseDown={this.handleButtonPress}
onMouseUp={this.handleButtonRelease}
onMouseLeave={this.handleButtonRelease}>
Button
</div>
);
}
}