最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - React countdown timer using new Date() - Stack Overflow

programmeradmin1浏览0评论

I tried coding a countdown timer as follows.

Every second the getTime() function is called. In this function, I have a variable named finishhours and a variable named currentHours. Finishhours is equal to the time that the countdown timer should be zero. CurrentHours is equal to the current time.

To make calculations easier I format both variables in hours. For example, 10:45:32 will bee 10 + 45/60 + 32/3600 = 10,76.

From there I can calculate the remaining hours, minutes and seconds and assign these values to variables: rHour, rMin and rSec. These 3 variables are then used to display the remaining time on the screen.

The problem I am facing is that the function getTime() gets called multiple times every second. And the number of times it gets called increases exponentially. For example, after one second elapses the function is called 2 times, one second later the function is called 8 times, then 32 times, and so on.

This is my code:

import React, { useState } from 'react';
import '../Timer.css';

const startDate = new Date();
const Timer = ({ end }) => {
  const[rHour, setRHour] = useState(2); //countdown 2 hours.
  const[rMin, setRMin] = useState(0);
  const[rSec, setRSec] = useState(0);

  function getTime(){
    const finishHours = startDate.getHours() + 2 + startDate.getMinutes() / 60 + startDate.getSeconds() / 3600;
    const currentHours =  new Date().getHours() + new Date().getMinutes() / 60 + new Date().getSeconds() / 3600;
    const remainingHours = finishHours - currentHours;

    const remainingHour = Math.floor(remainingHours);
    const remainingMinute = Math.floor((remainingHours - remainingHour) * 60);
    const remainingSecond = Math.floor(((remainingHours - remainingHour) * 60 - remainingMinute)*60)

    setRHour(remainingHour);
    setRMin(remainingMinute);
    setRSec(remainingSecond);
    console.log("count")
  }

  setInterval(function(){
    getTime()
  }, 1000);

  return(
    <div className="timer-container">
      <div className="numbers">
        <span className = "num-span">{("0" + rHour).slice(-2)}</span>
        <span className = "segment">:</span>
        <span className = "num-span">{("0" + rMin).slice(-2)}</span>
        <span className = "segment">:</span>
        <span className = "num-span">{("0" + rSec).slice(-2)}</span>
      </div>
      <div class="sub-numbers">
        <span className = "sub-span">Uur</span>
        <span></span>
        <span className = "sub-span">Min</span>
        <span></span>
        <span className = "sub-span">Sec</span>
      </div>
    </div>
  );
};


export {Timer};

Is there a way I can prevent this? Thank you in advance.

I tried coding a countdown timer as follows.

Every second the getTime() function is called. In this function, I have a variable named finishhours and a variable named currentHours. Finishhours is equal to the time that the countdown timer should be zero. CurrentHours is equal to the current time.

To make calculations easier I format both variables in hours. For example, 10:45:32 will bee 10 + 45/60 + 32/3600 = 10,76.

From there I can calculate the remaining hours, minutes and seconds and assign these values to variables: rHour, rMin and rSec. These 3 variables are then used to display the remaining time on the screen.

The problem I am facing is that the function getTime() gets called multiple times every second. And the number of times it gets called increases exponentially. For example, after one second elapses the function is called 2 times, one second later the function is called 8 times, then 32 times, and so on.

This is my code:

import React, { useState } from 'react';
import '../Timer.css';

const startDate = new Date();
const Timer = ({ end }) => {
  const[rHour, setRHour] = useState(2); //countdown 2 hours.
  const[rMin, setRMin] = useState(0);
  const[rSec, setRSec] = useState(0);

  function getTime(){
    const finishHours = startDate.getHours() + 2 + startDate.getMinutes() / 60 + startDate.getSeconds() / 3600;
    const currentHours =  new Date().getHours() + new Date().getMinutes() / 60 + new Date().getSeconds() / 3600;
    const remainingHours = finishHours - currentHours;

    const remainingHour = Math.floor(remainingHours);
    const remainingMinute = Math.floor((remainingHours - remainingHour) * 60);
    const remainingSecond = Math.floor(((remainingHours - remainingHour) * 60 - remainingMinute)*60)

    setRHour(remainingHour);
    setRMin(remainingMinute);
    setRSec(remainingSecond);
    console.log("count")
  }

  setInterval(function(){
    getTime()
  }, 1000);

  return(
    <div className="timer-container">
      <div className="numbers">
        <span className = "num-span">{("0" + rHour).slice(-2)}</span>
        <span className = "segment">:</span>
        <span className = "num-span">{("0" + rMin).slice(-2)}</span>
        <span className = "segment">:</span>
        <span className = "num-span">{("0" + rSec).slice(-2)}</span>
      </div>
      <div class="sub-numbers">
        <span className = "sub-span">Uur</span>
        <span></span>
        <span className = "sub-span">Min</span>
        <span></span>
        <span className = "sub-span">Sec</span>
      </div>
    </div>
  );
};


export {Timer};

Is there a way I can prevent this? Thank you in advance.

Share Improve this question asked Jul 14, 2021 at 13:05 M.DeBaeckeM.DeBaecke 832 silver badges10 bronze badges 2
  • Can you please put a log in first line of Timer function. Timer function might be call multiple time rather then just getTime() – Mayur Kukadiya Commented Jul 14, 2021 at 13:09
  • 1 Your setInterval wants to be inside a useEffect.. – Keith Commented Jul 14, 2021 at 13:10
Add a ment  | 

3 Answers 3

Reset to default 2

Basically every render you are doing is creating a new setInterval, you only want a single setInterval when the ponent is mounted.

For things like this you want to use useEffect, useEffect also has a callback method you can use to clean up the setInterval when the ponent is unmounted.

So using this information.

try>

  useEffect(() => {
    const i = setInterval(getTime, 1000);
    return () => clearInterval(i);
  }, [end]);  //dependency, if end changes remount

You should set the interval in a useEffect. As on each setstate the ponent is being re-rendered and setting the interval again.

useEffect(()=>{
 setInterval(()=>{
    getTime()
  }, 1000);
},[]);

Try this code : UseEffect will set this interval once even Timer function call multiple time. then after setInterval will call again and again.

import React, { useState } from 'react';
import '../Timer.css';

const startDate = new Date();
const Timer = ({ end }) => {
  const[rHour, setRHour] = useState(2); //countdown 2 hours.
  const[rMin, setRMin] = useState(0);
  const[rSec, setRSec] = useState(0);

  function getTime(){
    const finishHours = startDate.getHours() + 2 + startDate.getMinutes() / 60 + startDate.getSeconds() / 3600;
    const currentHours =  new Date().getHours() + new Date().getMinutes() / 60 + new Date().getSeconds() / 3600;
    const remainingHours = finishHours - currentHours;

    const remainingHour = Math.floor(remainingHours);
    const remainingMinute = Math.floor((remainingHours - remainingHour) * 60);
    const remainingSecond = Math.floor(((remainingHours - remainingHour) * 60 - remainingMinute)*60)

    setRHour(remainingHour);
    setRMin(remainingMinute);
    setRSec(remainingSecond);
    console.log("count")
  }

  useEffect(()=>{
    setInterval(function(){
      getTime()
    }, 1000);
  }, []);

  return(
    <div className="timer-container">
      <div className="numbers">
        <span className = "num-span">{("0" + rHour).slice(-2)}</span>
        <span className = "segment">:</span>
        <span className = "num-span">{("0" + rMin).slice(-2)}</span>
        <span className = "segment">:</span>
        <span className = "num-span">{("0" + rSec).slice(-2)}</span>
      </div>
      <div class="sub-numbers">
        <span className = "sub-span">Uur</span>
        <span></span>
        <span className = "sub-span">Min</span>
        <span></span>
        <span className = "sub-span">Sec</span>
      </div>
    </div>
  );
};


export {Timer};
发布评论

评论列表(0)

  1. 暂无评论