clattenburg cake
clattenburg cake

Reputation: 1222

React Hooks Clock - Clear SetInterval After Certain Time

I have a stopwatch function in React that I would like to stop after 15 minutes. I am not sure how to use clearInterval() in this case:

  const [timer, setTimer] = useState(0);
  const [isActive, setIsActive] = useState(false);
  const [isPaused, setIsPaused] = useState(false);
  const countRef = useRef(null);
  const lastUpdatedRef = useRef(null);
  const [minutes,setMinutes] = useState(0)
  const [seconds,setSeconds] = useState(0)


  const timeCeiling = 900; //maximum minutes is 15
  const timeFloor = 60; //maximum seconds is 60 so it resets after

  useEffect(() => {
    if (timer < timeCeiling) {
      setMinutes(Math.floor(timer / 60));
      setSeconds(timer % 60);
    } else {
      setMinutes(15);
      setSeconds(0);
    }
  }, [timer]);


  const handleStart = () => {
    setIsActive(true);
    setIsPaused(true);
    countRef.current = setInterval(() => {
      setTimer((timer) => timer + 1);
    }, 1000);
    lastUpdatedRef.current = setInterval(() => {
      setLastUpdated(Date.now());
    }, 30000);
  };

The user clicks on the handleStart function which triggers a useEffect. It also has a lastUpdated dependency which triggers another function every 30 seconds.

The clock should end after 15:00 but it still continues after- where should I put clearInterval so that it stops the clock after 15 minutes? Or is there another way to do this?

Upvotes: 3

Views: 1146

Answers (3)

Viet
Viet

Reputation: 12787

You can add cleare interval in the else condition:

useEffect(() => {
  if (timer < timeCeiling) {
    setMinutes(Math.floor(timer / 60));
    setSeconds(timer % 60);
  } else {
    setMinutes(15);
    setSeconds(0);
    countRef.current && clearInterval(countRef.current);
    lastUpdatedRef.current && clearInterval(lastUpdatedRef.current);
  }
}, [timer]);

And you should cleare interval when component un-mount:

useEffect(() => {
  return () => {
    countRef.current && clearInterval(countRef.current);
  };
}, [countRef]);

useEffect(() => {
  return () => {
    lastUpdatedRef.current && clearInterval(lastUpdatedRef.current);
  };
}, [lastUpdatedRef]);

Upvotes: 1

Usman Sabuwala
Usman Sabuwala

Reputation: 900

I think you should use clearInterval in the else block in useEffect. Maybe this way:

else {
  setMinutes(15);
  setSeconds(0);
  clearInterval(countRef.current) // I hope this works
}

Upvotes: 1

Drew Reese
Drew Reese

Reputation: 202706

I would place it in the useEffect that is running each time timer updates. Clear the interval in the else branch when the limit it hit.

useEffect(() => {
  if (timer < timeCeiling) {
    setMinutes(Math.floor(timer / 60));
    setSeconds(timer % 60);
  } else {
    clearInterval(countRef.current);
    setMinutes(15);
    setSeconds(0);
  }
}, [timer]);

You might also want to add an additional useEffect hook to clear any running timers should the component unmount before you manually clear them.

useEffect(() => {
  return () => {
    clearInterval(countRef.current);
    clearInterval(lastUpdatedRef.current);
  };
}, []);

Upvotes: 2

Related Questions