Reputation: 179
Im trying to implement a timer to distinguish between single click and dbl click events so the single click does not fire when dbl clicking.
Edit: I should clarify, I want the component to react differently to single/double clicks, the Double click is working, but when I double click it also fires a single click event. I want to ignore the single click when during a double click
export const useNoClickOnDblClick = (onClick: () => void, onDoubleClick: () => void) => {
const [clicks, setClicks] = useState(0);
useEffect(() => {
let singleClickTimer: string | number | NodeJS.Timeout | undefined;
if (clicks === 1) {
singleClickTimer = setTimeout(function () {
onClick();
setClicks(0);
}, 250);
} else if (clicks === 2) {
onDoubleClick();
setClicks(0);
}
return () => clearTimeout(singleClickTimer);
}, [clicks]);
return {
clicks,
setClicks
};
};
Not sure if this is the best way, but I came across this implementations near the bottom of this thread, https://github.com/facebook/react/issues/3185
It seems to work for basic usage, functions that have no parameters, like below
const { setClicks } = useNoClickOnDblClick(handleRenderInfo, () => console.log('dbl click'));
<SummaryCard
data={data}
onCardClick={() => setClicks((prev) => prev + 1)}
/>
However I want to do something like this, where I need to pass in different data for each card
const { setClicks } = useNoClickOnDblClick(handleRenderLevelInfo, () => console.log('dbl click'));
{mineData.levelArr.map((level, i) => {
return (
<MineCard
key={i}
data={level}
onCardClick={() => setClicks((prev) => prev + 1)}
//onCardClick={() => handleRenderLevelInfo({ ...level, idx: i })}
onCardDblClick={() =>
navigateTo({ path: `/${surveyPointsPrefix}/${mineID}/${level.level}` })
}
/>
);
})}
How do I go about passing in the level data from the .map? I know I can pass the entire thing into the customHook along with the single/double click, But I feel like it will get pretty messy if I am trying to reuse the hook etc.
Thanks for any help.
Upvotes: 1
Views: 1983
Reputation: 547
You can use this custom hook:
export const useDoubleClick = (onClick, onDbClick, delay = 300) => {
const timePassed= useRef(0);
return (e) => {
if (e.detail === 1) {
setTimeout(() => {
if (Date.now() - timePassed.current >= delay) {
onClick();
}
}, delay)
}
if (e.detail === 2) {
timePassed.current = Date.now();
onDbClick();
}
}
}
And in then use it like this:
const onClick = () => console.log('click')
const onDoubleClick = () => console.log('double click')
const myDoubleClickCallback = useDoubleClick(onClick, onDoubleClick);
And add myDoubleClickCallback to the component:
<div onClick={myDoubleClickCallback}>Click Me</div>
Upvotes: 2
Reputation: 402
singleClickMethod () {};
doubleClickMethod () {};
hasDoubleClick = false:
onClickHandler (event) {
event.preventDefault();
event.stopPropagation();
setTimeout(() => {
if (hasDoubleClick) {
hasDoubleClick = false;
return;
}
singleClickMethod();
});
};
onDblClickHandler () {
hasDoubleClick = true;
doubleClickMethod();
}
Such approach is going to work for you and distinguish the click events.
Upvotes: 0