DelayedButton.jsx 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. import React, { useEffect, useRef, useState } from "react";
  2. const useCountdown = (seconds, onEnd) => {
  3. const [finished, setFinished] = useState(false);
  4. const [remaining, setRemaining] = useState(seconds);
  5. const [paused, setPaused] = useState(false);
  6. const remainingMut = useRef(seconds);
  7. useEffect(() => {
  8. const timer = setInterval(() => {
  9. if (!paused) {
  10. setRemaining((remainingMut.current -= 1));
  11. }
  12. }, 1000);
  13. return () => clearInterval(timer);
  14. }, [paused]);
  15. useEffect(() => {
  16. if (!finished && remaining <= 0) {
  17. onEnd();
  18. setFinished(true);
  19. }
  20. }, [finished, remaining, onEnd]);
  21. return [remaining, () => setPaused(!paused)];
  22. };
  23. const CountdownButton = ({
  24. onCancelled,
  25. onEnd,
  26. formatter,
  27. seconds,
  28. autoFocus,
  29. buttonClass,
  30. }) => {
  31. const [remaining, pause] = useCountdown(seconds, onEnd);
  32. return (
  33. <button
  34. type="button"
  35. className={buttonClass}
  36. autoFocus={autoFocus}
  37. onClick={() => {
  38. pause();
  39. onCancelled();
  40. }}
  41. >
  42. {formatter(remaining)}
  43. </button>
  44. );
  45. };
  46. const DelayedButton = ({
  47. children,
  48. onEnd,
  49. countDownFormatter,
  50. seconds,
  51. autoFocus,
  52. buttonClass,
  53. }) => {
  54. const [delayed, setDelayed] = useState(false);
  55. return delayed ? (
  56. <CountdownButton
  57. onCancelled={() => setDelayed(false)}
  58. onEnd={onEnd}
  59. formatter={countDownFormatter ?? JSON.stringify}
  60. seconds={seconds ?? 3}
  61. autoFocus={autoFocus}
  62. buttonClass={buttonClass}
  63. />
  64. ) : (
  65. <button
  66. type="button"
  67. className={buttonClass}
  68. autoFocus={autoFocus}
  69. onClick={() => setDelayed(true)}
  70. >
  71. {children}
  72. </button>
  73. );
  74. };
  75. export default DelayedButton;