Countdown timer does not show zeros values. When seconds or minutes approaching zero, timer delete span, where showing value. If timer time 7 minutes 00 seconds he shows 7, but i need minutes 07 seconds 00
Time used React hooks.
Code
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>
);
}
This check prevent the rendering of the interval
for every falsy value, which means that 0
won't be rendered as well:
if (!timeLeft[interval]) {
return;
}
You should check if the value is undefined
to skip rendering, although it's redundant your case. An empty object would produce an empty array of keys, which means that the forEach
callback won't be invoked.
if (timeLeft[interval] === undefined) {
return;
}
Demo:
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;
}
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] === undefined) {
return;
}
return (
<span key={interval}>
{timeLeft[interval]} {interval}{" "}
</span>
);
});
return timerComponents;
}
ReactDOM.render(
<App />,
root
);
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<div id="root"></div>
Another option is to avoid creating all timerComponents
if timeLeft
is null
(instead of setting an empty object):
function calculateTimeLeft() {
const year = new Date().getFullYear();
const difference = +new Date(`${year}-10-1`) - +new Date();
return difference > 0 ?
{
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)
} : null;
}
function App() {
const [timeLeft, setTimeLeft] = React.useState(calculateTimeLeft());
React.useEffect(() => {
const id = setTimeout(() => {
setTimeLeft(calculateTimeLeft());
}, 1000);
return () => {
clearTimeout(id);
};
});
if(!timeLeft) return null;
return Object.keys(timeLeft).map(interval => (
<span key={interval}>
{timeLeft[interval]} {interval}{" "}
</span>
));
}
ReactDOM.render(
<App />,
root
);
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<div id="root"></div>