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.