1

I'm trying to create a button, which on hold shows a countdown of 3 seconds, if kept on hold for 3 seconds it shows an alert, but for some reason the countdown doesn't reset properly AND the alert fires up anyway, at every click (after the timeout)

my code is:

const [showCountdown, setShowCountdown] = useState(false)
const [holdTimer, setHoldTimer] = useState(3)

var timer = 0, interval;
const refreshDown = () => {
    setShowCountdown(true)
    interval = setInterval(function(){       
        setHoldTimer((t) => t - 1)
    },1000);
    timer = setTimeout(function(){
        if (confirm('Refresh page?')){
            window.location.reload()
        }
    },3000)
}
const refreshUp = () => {
    clearTimeout(timer)
    clearInterval(interval)
    setShowCountdown(false)
    setHoldTimer(3)
}

my html button has these two:

<svg onMouseDown={() => refreshDown()} onMouseUp={() => refreshUp()}>
  ...
</svg>
Nathan Bernard
  • 391
  • 2
  • 7
  • 22
  • That's an odd way to implement the task. However, I can suppose that the problem is given by React firing the events twice because in strict mode. The variable `timer` gets overridden, thus only one of the two timeouts get cleared – Christian Vincenzo Traina Jan 04 '23 at 21:38
  • Check out [this question](https://stackoverflow.com/questions/50819162/why-is-my-function-being-called-twice-in-react) – Christian Vincenzo Traina Jan 04 '23 at 21:39

2 Answers2

1

Have you tried with useRef ?

const timer = useRef();
  const interval = useRef();
  const refreshDown = () => {
    setShowCountdown(true);
    interval.current = setInterval(function () {
      setHoldTimer((t) => t - 1);
    }, 1000);
    timer.current = setTimeout(function () {
      if (confirm("Refresh page?")) {
        window.location.reload();
      }
    }, 3000);
  };
  const refreshUp = () => {
    clearTimeout(timer.current);
    clearInterval(interval.current);
    setShowCountdown(false);
    setHoldTimer(3);
  };
OneQ
  • 1,149
  • 1
  • 8
  • 15
1

React component is rerendered each time state or props are changed. When setHoldTimer is executed, it changes the state. It causes reexecuttion of component’s code, so local variables “timer” and “interval” are declared again with values “0” and “undefined”, also new “refreshUp” function is created referencing new “timer” and “interval”. When you release the mouse, new “refreshUp” is called, interval and timeout are not cleared.

Try to define timer and interval as a state or with “useRef”. This way they will not be redefined during rerender.