Home > Software engineering >  how to set/reset 'useInterval' upon button press or tab change
how to set/reset 'useInterval' upon button press or tab change

Time:08-16

I am building Pomodoro timer and I am having trouble with useIntervel hook. I want to both be able to reset the useInterval so that the timer should stop when reset button is pressed or I navigate to another tab (I am using bottom tab navigation) and restart when the start button is pressed or I re-navigate to the timer tab. I can stop the useInterval hook thanks to the article: [1]: React hooks useInterval reset after button click

However, once stopped I can't reactivate it.

I tried the following but it didn't work as it throws the "invalid hook call" error:

function useInterval (callback, delay){
// rest of the code
}

useEffect(()=> {
  const interval = useInterval(callback, delay)
}, [start])

In the above link "Jacki" mentions that

Reset actually stop but doesn't start new interval but I figured out how to do so thanks to your answer and now everything works fine. Thank you!

However he hasn't shared a solution which is what I want.

CodePudding user response:

I would implement a custom hook that manages an internal start and stop state.

Here is a minimal example. The delay prop is the input for the setInterval function. The callback prop is a function that is called on each interval tick.

export function useInterval(callback, delay) {
 const savedCallback = useRef();

  const [start, setStart] = useState(false)

  // Remember the latest callback.
  useEffect(() => {
    savedCallback.current = callback;
  }, [callback]);

  // Set up the interval.
  useEffect(() => {
    if (start) {
      const tick = () => {
          savedCallback.current();
      }
      if (delay !== null) {
        const id = setInterval(tick, delay);
        return () => clearInterval(id);
      }
    }
  }, [delay, start]);

  const startTimer = React.useCallback((shouldStart) => {
    setStart(shouldStart)
  }, []);

  return startTimer;
}

You can use it as follows.

export default function App() {
  const [timer, setTimer] = useState(0);
  const startTimer = useInterval(() => setTimer(prev => prev   1), 100)
  
  return (
    <View style={{margin:50}}>
      <Pressable onPress={() => startTimer(true)}> <Text>Start</Text></Pressable>
      <Pressable onPress={() => startTimer(false)}> <Text>Stop</Text></Pressable>
      <Pressable onPress={() => setTimer(0)}><Text>Reset</Text></Pressable>

      <Text>{timer}</Text>
    </View>
  );
}

Here is a little snack. You can start, stop and reset the timer via the buttons.

  • Related