Khoa Nguyễn
Khoa Nguyễn

Reputation: 119

I'm having trouble in making a countdown timer (Reactjs )

I'm using Reactjs to make a countdown timer that can separate to day, hours, minutes, and seconds between 2 dates. It works fine, but It can only count to a date that is larger than the current date (21/08/2022 < 17/10/2022), but It cannot count to (21/08/2022 to 21/08/2023). I have a function to pass down props:

const timeLeft = useCountdown(new Date(2022, Data.date.month , Data.date.day));  

It should look like this when console.log:

{days: 87, hours: 20, minutes: 58, seconds: 40}

I'm using a useCountDown hook to count the time between 2 dates:

import { useState, useEffect } from "react";

const useCountdown = (deadline) => {
    const [days, setDays] = useState(0);
    const [hours, setHours] = useState(0);
    const [minutes, setMinutes] = useState(0);
    const [seconds, setSeconds] = useState(0);
  
    const leading0 = (num) => {
      return num < 10 ? "0" + num : num;
    };
  
    const getTimeUntil = (deadline) => {
      const time = Date.parse(deadline) - Date.parse(new Date());
      if (time < 0) {
        setDays(0);
        setHours(0);
        setMinutes(0);
        setSeconds(0);
      } else {
        setDays(Math.floor(time / (1000 * 60 * 60 * 24)));
        setHours(Math.floor((time / (1000 * 60 * 60)) % 24));
        setMinutes(Math.floor((time / 1000 / 60) % 60));
        setSeconds(Math.floor((time / 1000) % 60));
      }
    };
  
    useEffect(() => {
      setInterval(() => getTimeUntil(deadline), 1000);
  
      return () => getTimeUntil(deadline);
    }, [deadline]);
    
    return {
        days: leading0(days),
        hours: leading0(hours),
        minutes: leading0(minutes),
        seconds: leading0(seconds)
    };
};

export default useCountdown;

I haven't figured out how to fix this. Sorry for the bad English, but I'm trying my best :( Thank you for helping me!

Upvotes: 1

Views: 1048

Answers (1)

Chris Hamilton
Chris Hamilton

Reputation: 10994

Here's a much simpler version:

const useCountdown = (deadline: Date) => {
  // Time is in seconds
  const [time, setTime] = useState(
    Math.max(0, Math.floor((deadline.getTime() - Date.now()) / 1000))
  );

  const decrement = () =>
    setTime((prevTime) => {
      return prevTime === 0 ? 0 : prevTime - 1;
    });

  useEffect(() => {
    const id = setInterval(decrement, 1000);
    return () => clearInterval(id);
  }, []);

  const format = (num: number): string => {
    return num < 10 ? '0' + num : num.toString();
  };

  return {
    days: format(Math.floor(time / (3600 * 24))),
    hours: format(Math.floor((time / 3600) % 24)),
    minutes: format(Math.floor((time / 60) % 60)),
    seconds: format(time % 60),
  };
};

Stackblitz: https://stackblitz.com/edit/react-ts-bnhvxp?file=App.tsx

Upvotes: 3

Related Questions