0

I'm building a component that renders the elapsed time from a given date. The date is a timestamp, for example, 1600836722.

Here is what I have so far:

const FORMAT_PATTERN = "DD/MM/YYYY HH:mm:ss"; export default function Timer({ dateCreated }) { const [hours, setHours] = useState(0); const [minutes, setMinutes] = useState(0); const [seconds, setSeconds] = useState(0); const [startTime, setStartTime] = useState(); useEffect(() => { const orderTimestamp = Moment.unix(dateCreated); setStartTime(Moment(orderTimestamp, FORMAT_PATTERN)); }, [dateCreated]); useEffect(() => { let interval = null; interval = setInterval(() => { const now = Moment(Date.now()); const difference = Moment.duration( Moment(now, FORMAT_PATTERN).diff(startTime) ); setHours(Math.floor(difference.asHours())); // this is so that 1 day, 12 hours will be 34 hours setMinutes(Moment.utc(now.diff(startTime)).format("mm")); setSeconds(Moment.utc(now.diff(startTime)).format("ss")); }, 1000); return () => clearInterval(interval); }, [hours, minutes, seconds]); return hours && seconds && minutes ? ( <Typography>{[hours, minutes, seconds].join(":")}</Typography> ) : null; } 

It works, displays the time just fine but there will be multiple components on the same page that track the elapsed time and my approach does not seem the most optimized. Any ideas?

3
  • Can you be more specific why do you think it is not optimized? Or do you have any actual performance issue? Such generic thought can be answered many ways from "it may be perfectly OK for your usage" to "oh god rewrite to vanilla JS, React is not the most optimized framework itself!" :) Commented Sep 25, 2020 at 7:25
  • I think that the multiple calls to Moment.duration() every second, from 10 of these timers will get overwhelming for browsers running on slower computers. Commented Sep 25, 2020 at 7:27
  • why do you think it will get overwhelming compared to the rest of the setInterval handler? Do you have some benchmark? Commented Sep 25, 2020 at 12:13

1 Answer 1

2

I think this could be simplified much further into something like this. The value you render is dependent only on the current time.

You do not require multiple states since the hours, seconds, days-- what have you -- all else could just be derived from the Date.now()(date right now) .

function calculateTimeLeft() { const year = new Date().getFullYear(); const difference = +new Date(`${year}-10-1`) - +new Date(); let timeLeft = {}; if (difference > 0) { timeLeft = { days: Math.floor(difference / (1000 * 60 * 60 * 24)), hours: Math.floor((difference / (1000 * 60 * 60)) % 24), minutes: Math.floor((difference / 1000 / 60) % 60), seconds: Math.floor((difference / 1000) % 60) }; } return timeLeft; } export default function App() { const [timeLeft, setTimeLeft] = React.useState(calculateTimeLeft()); React.useEffect(() => { const id = setTimeout(() => { setTimeLeft(calculateTimeLeft()); }, 1000); return () => { clearTimeout(id); }; }); const timerComponents = Object.keys(timeLeft).map(interval => { if (!timeLeft[interval]) { return; } return ( <span> {timeLeft[interval]} {interval}{" "} </span> ); }); return ( <div> {timerComponents.length ? timerComponents : <span>Time's up!</span>} </div> ); } 

You could see the working example here :- https://stackblitz.com/edit/react-t86icp

Sign up to request clarification or add additional context in comments.

1 Comment

I'll give it a go. Thanks, @Prateek Thapa!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.