new to react here. I'm trying to output a countdown timer to a date that is set to 5 minutes from now. But all I was able to get was either the countdown rubber banding, or static on 5 minutes or 0. Currently, it is static on 00:00:00:00. Thanks
EDIT: I'm trying to make it work with hooks instead of through a constructor class.
import AButton from './aButton'; import { useState, useRef, useEffect} from 'react';
export default function Countdown() { const [addTime, setAddtime] = useState(); const [countdown, setCountdown] = useState((new Date()).toLocaleTimeString()); const [timerDays, setDays] = useState('00'); const [timerHours, setHours] = useState('00'); const [timerMinutes, setMinutes] = useState('00'); const [timerSeconds, setSeconds] = useState('00'); let interval = useRef(); const oldDateObject = new Date(); const sourceDate = oldDateObject.getTime(); // date - 300000 const diff = 5; //this gives use the unix timestamp of the future date which is the current date + 5 minutes const futureDate = new Date(oldDateObject.getTime() + diff*60000); //300000 const convertToDate = (date, hours, minutes, seconds) => { date = new Date(sourceDate * 1000); // Hours part from the timestamp hours = date.getHours(); // Minutes part from the timestamp minutes = ("0" + date.getMinutes()).substr(-2); // Seconds part from the timestamp seconds = ("0" + date.getSeconds()).substr(-2); return hours + ':' + minutes.substr(-2) + ':' + seconds.substr(-2); } const startTimer = () => { const timeUpdate = new Date().getTime(convertToDate); interval = setInterval(() => { const now = new Date().getTime(); const timeDifference = timeUpdate - now; //this converts the unix code of the future date to each clock element every second const days = Math.floor(timeDifference / (24 * 60 * 60 * 1000)); const hours = Math.floor(timeDifference % (24 * 60 * 60 * 1000) / (60 * 60 * 1000));; const minutes = Math.floor(timeDifference % (60 * 60 * 1000) / (60 * 1000));; const seconds = Math.floor(timeDifference % (60 * 1000) / 1000);; if (timeDifference < 0) { clearInterval(interval.current); } else { setDays(days); setHours(hours); setMinutes(minutes); setSeconds(seconds); } }, 1000); }; useEffect(() => { startTimer(); return () => { clearInterval(interval.current); }; }); return ( <div> <h1>{countdown === null ? <span style={{padding: '50px'}}></span> : countdown}</h1> <button onClick={ () => setCountdown(countdown !== null ? null : ( new Date()).toLocaleTimeString())}>{countdown === null ? 'Show' : 'Hide'}</button> <div>----------------</div> <h1>{timerDays} : {timerHours} : {timerMinutes} : {timerSeconds}</h1> <button>Activate countdown</button> </div> ) } 12 Answers
I think you are making it way more complicated than it needs to be.
Store a state of a 5 minute countdown (in seconds) and a second piece of state to start/run the timer.
When the timer is started seed the countdown state with 5 minutes (it will expire from the current point in time).
Compute the derived and formatted time from the single countdown state.
function App() { const [countDown, setCountDown] = React.useState(0); const [runTimer, setRunTimer] = React.useState(false); React.useEffect(() => { let timerId; if (runTimer) { setCountDown(60 * 5); timerId = setInterval(() => { setCountDown((countDown) => countDown - 1); }, 1000); } else { clearInterval(timerId); } return () => clearInterval(timerId); }, [runTimer]); React.useEffect(() => { if (countDown < 0 && runTimer) { console.log("expired"); setRunTimer(false); setCountDown(0); } }, [countDown, runTimer]); const togglerTimer = () => setRunTimer((t) => !t); const seconds = String(countDown % 60).padStart(2, 0); const minutes = String(Math.floor(countDown / 60)).padStart(2, 0); return ( <div className="App"> <div> Time: {minutes}:{seconds} </div> <button type="button" onClick={togglerTimer}> {runTimer ? "Stop" : "Start"} </button> </div> ); } const rootElement = document.getElementById("root"); ReactDOM.render( <App />, rootElement );.App { font-family: sans-serif; text-align: center; }<script src=""></script> <script src=""></script> <div></div>3look at
and
1