A simple hook that waits for a boolean to be true
to begin counting. The count is controlled by a function that can remain in the function component. This hook will continue to pass true
to the function until the starting number time
is equal to the final number limit
. It is recommended to remain outside and imported to a function component.
import { useEffect } from "react";
/**
* Timer ~ Count up or down
* @param {boolean} bool if true, start the timer
* @param {function} fn to control the count outside of useEffect (ex: + 2, - 1, etc.)
* @param {number} time a staring number that will count down or up
* @param {number} limit the last number to reach
*/
const useTimer = (bool, fn, time = 0, limit = 0) => {
useEffect(() => {
const timer = setTimeout(() => fn(true), 1000);
if (bool) {
if (time === limit) {
fn(false);
clearTimeout(timer);
}
} else {
return clearTimeout(timer);
}
}, [bool, fn, time, limit]);
};
export default useTimer;
I have a working example for counting up or down. Here's how we can count down.
import React, { useState } from "react";
import useTimer from "../hooks/useTimer";
const CountDown = () => {
const [start, setStart] = useState(false);
const [time, setTime] = useState(10);
const handleTime = (bool) => {
if (bool) {
setTime(() => time - 1);
} else {
setTime(() => 10);
setStart(false);
}
};
useTimer(start, handleTime, time); // limit is 0 by default
return (
<div>
<h2>{time}</h2>
<button onClick={() => setStart(!start)}>Count Down</button>
</div>
);
};
export default CountDown;
We're expecting this to count down from 10 to 0 and stop.
const [start, setStart] = useState(false);
const [time, setTime] = useState(10);
Next is the function useTimer
will call. If start is true, decrease the time by 1
, when it finally reaches zero - reset the boolean and time to their default values.
const handleTime = (bool) => {
if (bool) {
setTime(() => time - 1);
} else {
setTime(() => 10);
setStart(false);
}
};
What's nice is that even if we didn't set anything, by default our hook will clear the timeout safely! You can also trigger different timers and it seems like it's working fairly well.