Reputation: 1330
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?
Upvotes: 0
Views: 1259
Reputation: 4938
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
Upvotes: 2