react-timer-hook icon indicating copy to clipboard operation
react-timer-hook copied to clipboard

restart Function not working as Expected

Open prpercival opened this issue 3 years ago • 11 comments

If I call restart after the timer has already expired, the timer updates to the new Date but it doesn't start counting down.

Simple Example:

const [hasTimeExpired, setHasTimeExpired] = useState(false);

let dt = new Date();

const {
    seconds,
    minutes,
    hours,
    days,
    isRunning,
    start,
    pause,
    resume,
    restart,
} = useTimer({ expiryTimestamp: dt, onExpire: () => setHasTimeExpired(true), autoStart: false });

useEffect(() => {
    let dt = new Date();

    dt.setSeconds(dt.getSeconds() + 15);

    restart(dt, true);
}, [])

useEffect(() => {
    let dt = new Date();
    dt.setSeconds(dt.getSeconds() + 120);

    restart(dt, true);
}, [hasTimeExpired])

return (
    <div className= "Clock-Wrapper">
        <span className="Clock-Time-Front">
            {hours}:{minutes}:{seconds}
        </span>
    </div>
)

prpercival avatar Oct 25 '21 19:10 prpercival

Hi @prpercival, did you make any progress with this? I have the same issue and want to restart the timer after it has expired.

Interestingly, the 'restart' button in the official demo site does reset+start the 10 minute timer after first expiry. Also, the onExpire does not seem to be doing anything strange.

erikcvisser avatar Dec 01 '21 21:12 erikcvisser

@erikcvisser After playing around with it, I found that the timer will only restart if you re-render the component your timer is in when updating the time. Not an ideal solution, but it enabled me to reset the timer.

prpercival avatar Dec 01 '21 21:12 prpercival

use setTimeout()

setTimeout(() => { restart((new Date().setSeconds(new Date().getSeconds() + 50))); }, 1000)

sjwen98 avatar Dec 03 '21 02:12 sjwen98

@sjwen98 easy but effective - thanks!

erikcvisser avatar Dec 07 '21 19:12 erikcvisser

one more solution (when restart func called outside of onExpire callback it works fine):

...
  const { seconds, minutes, isRunning, restart } = useTimer({
    expiryTimestamp: time,
  });

  if (isRunning === false) {
    const time1 = new Date();
    time1.setSeconds(time1.getSeconds() + 1800); // 30 minutes timer

    restart(time1);
  }
...

ygr1k avatar Jan 14 '22 09:01 ygr1k

Any hope of this getting patched sometime soon? While there are ways to hack around this its frustrating to have to do it to begin with.

jacinto123 avatar Feb 24 '22 21:02 jacinto123

Hello, I solved this problem like this:

export const TimerSixtySecond = ({ expiryTimestamp }) => { const onExpire = async () => { const time = await new Date(); time.setSeconds(time.getSeconds() + 60); restart(time, true); resume; };

const { seconds, minutes, hours, days, isRunning, start, pause, resume, restart, } = useTimer({ expiryTimestamp, onExpire: () => onExpire(), autoStart: true, });

return ( <Text Text color="red.500" fontWeight="bold" fontSize={["5xl", "8xl"]}> {minutes}:{seconds}

); };

mrmidaw avatar Aug 09 '22 07:08 mrmidaw

As @prpercival said, it's only going to restart the timer if the component is re-rendered. An easy workaround then is to flip a boolean in state in the onExpire (causing a re-render), and have a useEffect restart the timer when that piece of state changes. This will restart the timer on a loop, but you can add logic to the useEffect & onExpire callback if you want to conditionally restart:

const Timer = ({ expiryTimeStamp }) => {

    const [flipState, setFlipState] = useState(true);

    useEffect(() => {
        const time = new Date();
        time.setSeconds(time.getSeconds() + 10);
        restart(time);
    }, [flipState])

    const {
        seconds,
        minutes,
        hours,
        days,
        isRunning,
        start,
        pause,
        resume,
        restart,
    } = useTimer({ expiryTimestamp, onExpire: () => setFlipState(!flipState) });


    return (
        <div style={{ textAlign: 'center' }}>
            <div style={{ fontSize: '50px' }}>
                <span>{seconds}</span>
            </div>
        </div>
    );
}

BenLooper avatar Sep 23 '22 13:09 BenLooper

Still happening in 2023, boolean state flip works as a workaround 👍

devonpmack avatar Mar 22 '23 00:03 devonpmack

The setTimeout() mentioned above is an easy work around!

PlacidSerene avatar Sep 25 '23 21:09 PlacidSerene

Quite disappointing, despite the workarounds above solving the issue.

SSopin avatar Oct 18 '23 00:10 SSopin