Closed Chris-Imade closed 2 weeks ago
Hello, thanks for your input! Could you elaborate on what caused you to spend the night on it?
It doesn't re-render when the prop does. This is brief I know, but I am working on this app where I need to display 15mins countdown on each 15mins interval of time, so when the countdown reaches 00:00:00 I pass the next 15mins interval to it so that it shows another 15mins countdown. In my case it never re-rendered. This made me try different ways to force it's re-render but to no avail.
There was also a scenario where before it updated there'd be a 47sec or there about delay.
Suggested fix:
I'll share code to how my issue was resolved...:
` interface CountdownProps { dateTime: Date; }
const calculateTimeLeft = ( targetDate: Date, ): { hours: number; minutes: number; seconds: number } => { const now = new Date(); const difference = targetDate.getTime() - now.getTime();
if (difference <= 0) {
return { hours: 0, minutes: 0, seconds: 0 };
}
const hours = Math.floor(
(difference % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60),
);
const minutes = Math.floor((difference % (1000 * 60 * 60)) / (1000 * 60));
const seconds = Math.floor((difference % (1000 * 60)) / 1000);
return { hours, minutes, seconds };
};
const Countdown: React.FC
const token = useSelector((state: AppState) => state.data.token);
const dispatch = useDispatch();
const updateCountdown = () => {
const newTimeLeft = calculateTimeLeft(dateTime);
setTimeLeft(newTimeLeft);
if (
newTimeLeft.hours === 0 &&
newTimeLeft.minutes === 0 &&
newTimeLeft.seconds === 0
) {
if (!hasRunOnce) {
setHasRunOnce(true); // Mark as run
(async () => {
dispatch(getNext15());
const storedDrawList = localStorage.getItem("drawList");
if (storedDrawList && token) {
const drawList = JSON.parse(storedDrawList);
try {
await updateExpiredDrawIds(drawList, token);
} catch (error: any) {
console.log("Error updating draw IDs:", error.message);
}
}
})();
}
return;
}
// Schedule the next update
requestId.current = requestAnimationFrame(updateCountdown);
};
useEffect(() => {
// Start the countdown
requestId.current = requestAnimationFrame(updateCountdown);
// Clean up on unmount
return () => {
if (requestId.current) {
cancelAnimationFrame(requestId.current);
}
};
}, [dateTime]);
useEffect(() => {
const storedToken = localStorage.getItem("token");
if (storedToken) {
dispatch(setAccessToken(JSON.parse(storedToken)));
}
}, [dispatch]);
return (
<div>
<span>{String(timeLeft.hours).padStart(2, "0")}:</span>
<span>{String(timeLeft.minutes).padStart(2, "0")}:</span>
<span>{String(timeLeft.seconds).padStart(2, "0")}</span>
</div>
);
};
export default Countdown; `
Hi, thanks for following up on your initial message. There are a few ways how the countdown should re-render/reset. The guaranteed way is to use the React key
prop. For example, you can use the new date
value as the key
value.
The other ways include updating the date
prop, but that doesn't work according to you. I will take another look. The other one is by using the `api´. If you have an example to repo, please consider sharing, thank you.
I'll close this issue. If you have any other thoughts or questions, please feel free to re-open or create a new one!
If you have any issues with it. Just scrap it and use your own countdown timer.
` import React, { useEffect, useState } from 'react';
interface CountdownProps { dateTime: Date; onComplete?: () => void; }
const calculateTimeLeft = (targetDate: Date): { hours: number; minutes: number; seconds: number } => { const now = new Date(); const difference = targetDate.getTime() - now.getTime();
if (difference <= 0) { return { hours: 0, minutes: 0, seconds: 0 }; }
const hours = Math.floor((difference % (1000 60 60 24)) / (1000 60 60)); const minutes = Math.floor((difference % (1000 60 60)) / (1000 60)); const seconds = Math.floor((difference % (1000 * 60)) / 1000);
// Handle NaN scenario return { hours: isNaN(hours) ? 0 : hours, minutes: isNaN(minutes) ? 0 : minutes, seconds: isNaN(seconds) ? 0 : seconds, }; };
const Countdown: React.FC = ({ dateTime, onComplete }) => {
const [timeLeft, setTimeLeft] = useState(calculateTimeLeft(dateTime));
useEffect(() => { const interval = setInterval(() => { const newTimeLeft = calculateTimeLeft(dateTime); setTimeLeft(newTimeLeft);
}, [dateTime, onComplete]);
return (
); };
export default Countdown; `