useTimeout.tsx 1.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
  1. import {useCallback, useRef} from 'react';
  2. type Options = {
  3. onTimeout: () => void;
  4. timeMs: number;
  5. };
  6. function useTimeout({timeMs, onTimeout}: Options) {
  7. const timeoutRef = useRef<number>(null);
  8. const saveTimeout = useCallback((timeout: ReturnType<typeof setTimeout> | null) => {
  9. if (timeoutRef.current) {
  10. clearTimeout(timeoutRef.current);
  11. }
  12. // See: https://reactjs.org/docs/hooks-faq.html#is-there-something-like-instance-variables
  13. // @ts-expect-error
  14. timeoutRef.current = timeout;
  15. }, []);
  16. return {
  17. /**
  18. * Start the timer
  19. *
  20. * If there was a previous timer, then it will be cancelled.
  21. */
  22. start: useCallback(() => {
  23. saveTimeout(null);
  24. saveTimeout(setTimeout(onTimeout, timeMs));
  25. }, [onTimeout, saveTimeout, timeMs]),
  26. /**
  27. * Cancel the current timer
  28. *
  29. * Does not run the onTimeout callback.
  30. */
  31. cancel: useCallback(() => {
  32. saveTimeout(null);
  33. }, [saveTimeout]),
  34. /**
  35. * Stop the current timer
  36. *
  37. * Will run the onTimeout callback.
  38. */
  39. end: useCallback(() => {
  40. saveTimeout(null);
  41. onTimeout();
  42. }, [onTimeout, saveTimeout]),
  43. };
  44. }
  45. export default useTimeout;