Skip to content

Instantly share code, notes, and snippets.

@ecklf
Last active September 7, 2021 09:24
Show Gist options
  • Save ecklf/c5137cb9c7ea9af3ca9bd25c6efb20ca to your computer and use it in GitHub Desktop.
Save ecklf/c5137cb9c7ea9af3ca9bd25c6efb20ca to your computer and use it in GitHub Desktop.
Trigger an event after holding down an element for a duration
// Usage:
// const Button = () => {
// const { completion, ...bind } = useTimedEvent(() => { fire(); }, { duration: 1000 });
// return <button {...bind}>Button</button>;
// };
import { useEffect, useRef, useState } from "react";
const useTimedEvent = (
callback: (() => void) | (() => Promise<void>),
options?: { refreshRate?: number; duration?: number }
) => {
const timerId = useRef<any>(null);
const [progress, setProgress] = useState(0);
const refreshRate = options?.refreshRate ?? 10;
const triggerAt = (options?.duration ?? 1000) / refreshRate;
const completion = (progress / triggerAt) * 100;
useEffect(() => () => clearInterval(timerId.current), []);
useEffect(() => {
if (progress === triggerAt) {
endProgress();
callback();
}
}, [progress, triggerAt, callback]);
const startProgress = () => {
timerId.current = setInterval(
() => setProgress((val) => val + 1),
refreshRate
);
};
const endProgress = () => {
setProgress(0);
clearInterval(timerId.current);
};
const onMouseDown = () => {
startProgress();
};
const onTouchStart = () => {
startProgress();
};
const onMouseUp = () => {
endProgress();
};
const onMouseOut = () => {
endProgress();
};
const onTouchEnd = () => {
endProgress();
};
return {
completion,
onMouseDown,
onTouchStart,
onMouseUp,
onMouseOut,
onTouchEnd,
};
};
export default useTimedEvent;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment