I am making a countdown timer script in react.js. Before the timer starts, a 3 or 5 seconds countdown is displayed, data for both countdown becomes from another component. I am trying to stop/pause main countdown with a button. My problem is how can I control data from a function that is executed by useEffect()? I am trying crating a state for the btn, but the scope for the state is the useEffect
import TimerForm from './components/TimerForm';
const CountDown = (props) => {
const [timeLeft, setTimeLeft] = useState({
minutes: 0,
seconds: 0
});
const [counter, setCounter] = useState();
const [startTimer, setStartTimer] = useState(false);
const [result, setResult] = useState();
let Interval;
useEffect(() => {
let count = null;
if(startTimer){
if(counter === 0){
relog(result);
clearInterval(count);
return
}
count = setInterval(() => {
setCounter((prevcounter) => prevcounter - 1);
}, 1000);
return () => clearInterval(count);
} else {
clearInterval(count);
}
}, [startTimer, counter]);
const relog = useCallback((ForTime) => {
console.log(testing);
Interval = setInterval(() => {
setTimeLeft({
seconds: ForTime % 60,
minutes: Math.floor(ForTime / 60)% 60
});
if(ForTime === 0){
clearInterval(Interval);
return;
}
ForTime--;
},1000);
setStartTimer(false);
},[]);
const timerSettings = (data) => {
setCounter(data.counter);
setResult(data.result);
setStartTimer(true);
}
return (
<div>
<section>
<TimerForm onTimerSettings={timerSettings} />
<span>{counter}</span>
<div className="TimerClock">
<span>{timeLeft.minutes}</span><span>:</span><span>{timeLeft.seconds}</span>
</div>
<div>
<button type="button" className="btn btn-stop">Pause Button</button>
</div>
</section>
</div>
)
};
export default CountDown;```
create a useInterval hook used by useEffect() and useRef().
/**
*
* @param {Function} callback
* @param {number|null} delay, stopped when delay is null
*/
function useInterval(callback, delay) {
const savedCallback = useRef();
useEffect(() => {
savedCallback.current = callback;
});
useEffect(() => {
function tick() {
savedCallback.current();
}
if (delay !== null) {
let id = setInterval(tick, delay);
return () => clearInterval(id);
}
}, [delay]);
}
use useInterval
:
function App() {
const [delay, setDelay] = useState(null);
const [counter, setCounter] = useState(0);
useInterval(() => {
setCounter((counter) => counter - 1);
}, delay);
const handleChangeDelay = () => {
// stopped when delay is null
setDelay(delay === null ? 1000 : null);
};
return (
<div className="App">
<p>
<button onClick={handleChangeDelay}>trigger interval countdown</button>
</p>
<p>{counter}</p>
</div>
);
}