Coder Social home page Coder Social logo

amrlabib / react-timer-hook Goto Github PK

View Code? Open in Web Editor NEW
484.0 4.0 106.0 2.42 MB

React timer hook

Home Page: https://www.npmjs.com/package/react-timer-hook

License: MIT License

JavaScript 100.00%
react react-hooks timer countdown timers component hook react-native javascript stopwatch

react-timer-hook's Introduction

react-timer-hook

React timer hook is a custom react hook, built to handle timer, stopwatch, and time logic/state in your react component.

  1. useTimer: Timers (countdown timer)
  2. useStopwatch: Stopwatch (count up timer)
  3. useTime: Time (return current time)

Setup

yarn add react-timer-hook OR npm install --save react-timer-hook


useTimer - Demo

Example

import React from 'react';
import { useTimer } from 'react-timer-hook';

function MyTimer({ expiryTimestamp }) {
  const {
    totalSeconds,
    seconds,
    minutes,
    hours,
    days,
    isRunning,
    start,
    pause,
    resume,
    restart,
  } = useTimer({ expiryTimestamp, onExpire: () => console.warn('onExpire called') });


  return (
    <div style={{textAlign: 'center'}}>
      <h1>react-timer-hook </h1>
      <p>Timer Demo</p>
      <div style={{fontSize: '100px'}}>
        <span>{days}</span>:<span>{hours}</span>:<span>{minutes}</span>:<span>{seconds}</span>
      </div>
      <p>{isRunning ? 'Running' : 'Not running'}</p>
      <button onClick={start}>Start</button>
      <button onClick={pause}>Pause</button>
      <button onClick={resume}>Resume</button>
      <button onClick={() => {
        // Restarts to 5 minutes timer
        const time = new Date();
        time.setSeconds(time.getSeconds() + 300);
        restart(time)
      }}>Restart</button>
    </div>
  );
}

export default function App() {
  const time = new Date();
  time.setSeconds(time.getSeconds() + 600); // 10 minutes timer
  return (
    <div>
      <MyTimer expiryTimestamp={time} />
    </div>
  );
}

Settings

key Type Required Description
expiryTimestamp Date object YES this will define for how long the timer will be running
autoStart boolean No flag to decide if timer should start automatically, by default it is set to true
onExpire Function No callback function to be executed once countdown timer is expired

Values

key Type Description
seconds number seconds value
minutes number minutes value
hours number hours value
days number days value
totalSeconds number total number of seconds left in timer NOT converted to minutes, hours or days
isRunning boolean flag to indicate if timer is running or not
pause function function to be called to pause timer
start function function if called after pause the timer will continue based on original expiryTimestamp
resume function function if called after pause the timer will continue countdown from last paused state
restart function function to restart timer with new expiryTimestamp, accept 2 arguments first is the new expiryTimestamp of type Date object and second is autoStart of type boolean to decide if it should automatically start after restart or not, default is true

useStopwatch - Demo

Example

import React from 'react';
import { useStopwatch } from 'react-timer-hook';

function MyStopwatch() {
  const {
    totalSeconds,
    seconds,
    minutes,
    hours,
    days,
    isRunning,
    start,
    pause,
    reset,
  } = useStopwatch({ autoStart: true });


  return (
    <div style={{textAlign: 'center'}}>
      <h1>react-timer-hook</h1>
      <p>Stopwatch Demo</p>
      <div style={{fontSize: '100px'}}>
        <span>{days}</span>:<span>{hours}</span>:<span>{minutes}</span>:<span>{seconds}</span>
      </div>
      <p>{isRunning ? 'Running' : 'Not running'}</p>
      <button onClick={start}>Start</button>
      <button onClick={pause}>Pause</button>
      <button onClick={reset}>Reset</button>
    </div>
  );
}

export default function App() {
  return (
    <div>
      <MyStopwatch />
    </div>
  );
}

Settings

key Type Required Description
autoStart boolean No if set to true stopwatch will auto start, by default it is set to false
offsetTimestamp Date object No this will define the initial stopwatch offset example: const stopwatchOffset = new Date(); stopwatchOffset.setSeconds(stopwatchOffset.getSeconds() + 300); this will result in a 5 minutes offset and stopwatch will start from 0:0:5:0 instead of 0:0:0:0

Values

key Type Description
seconds number seconds value
minutes number minutes value
hours number hours value
days number days value
totalSeconds number total number of seconds in stopwatch NOT converted to minutes, hours or days
isRunning boolean flag to indicate if stopwatch is running or not
start function function to be called to start/resume stopwatch
pause function function to be called to pause stopwatch
reset function function to be called to reset stopwatch to 0:0:0:0, you can also pass offset parameter to this function to reset stopwatch with offset, similar to how offsetTimestamp will offset the initial stopwatch time, this function will accept also a second argument which will decide if stopwatch should automatically start after reset or not default is true

useTime - Demo

Example

import React from 'react';
import { useTime } from 'react-timer-hook';

function MyTime() {
  const {
    seconds,
    minutes,
    hours,
    ampm,
  } = useTime({ format: '12-hour'});

  return (
    <div style={{textAlign: 'center'}}>
      <h1>react-timer-hook </h1>
      <p>Current Time Demo</p>
      <div style={{fontSize: '100px'}}>
        <span>{hours}</span>:<span>{minutes}</span>:<span>{seconds}</span><span>{ampm}</span>
      </div>
    </div>
  );
}

export default function App() {
  return (
    <div>
      <MyTime />
    </div>
  );
}

Settings

key Type Required Description
format string No if set to 12-hour time will be formatted with am/pm

Values

key Type Description
seconds number seconds value
minutes number minutes value
hours number hours value
ampm string am/pm value if 12-hour format is used

Deprecation Warning:

Starting from v1.1.0 and above default export useTimer is deprecated, your old code will still work but it is better to start using named exports { useTimer, useStopwatch, useTime }

react-timer-hook's People

Contributors

amrlabib avatar dartess avatar dependabot[bot] avatar haleo9000 avatar izzlenizzle avatar kilokeith avatar ydhn avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

react-timer-hook's Issues

Please support returning miliseconds

Hi there,

I have run into a use case where i need the miliseconds value from the useTimer hook.

Is it possible to add this to the core library ? ( or i might take a jab at this myself )

Thanks :D

react native install issues

react-timer-hook lists react-dom as a peer dependency, and npm v7 installs peer dependencies by default. This makes clean react-native installs impossible, despite the tag on this repository.

Is react-dom a necessary dependency?

Is react-native supported?

Memoized callbacks from hooks

Hi!

Functions that return from the hook must be memoized because they can be used in effects, and the linter will require you to specify them depending. Now I had to memoize the functions myself, so as not to disable the linter. But after updating the linter, I still had to turn it off. Time to raise the problem.

Simple example (broken code):

    const {
        seconds,
        minutes,
        pause,
        restart,
    } = useTimer({
        expiryTimestamp: Date.now() + RE_SEND_AFTER_SECONDS * 1000,
        onExpire: () => setIsCanReSendSms(true),
    });

    useEffect(
        () => {
            if (screen === 'phoneConfirm') {
                restart(Date.now() + (RE_SEND_AFTER_SECONDS * 1000));
            } else {
                pause();
            }
        },
        [screen, pauseMemoized, restartMemoized],
    );

This will restart the effect with each renderer, because the functions are not memoized. Correct behavior - restarting the effect only when the variable "screen" is changed.

This can be added by removing callbacks from the dependencies. But this will force the developer to disable the linter, which is a bad decision in 99.9%.

Another solution is to add memoization yourself, but this is impractical and is now the reason for a new linter error. Now it looks like this.

    const {
        seconds,
        minutes,
        pause,
        restart,
    } = useTimer({
        expiryTimestamp: Date.now() + RE_SEND_AFTER_SECONDS * 1000,
        onExpire: () => setIsCanReSendSms(true),
    });

    // eslint-disable-next-line react-hooks/exhaustive-deps
    const pauseMemoized = useCallback(pause, []);
    // eslint-disable-next-line react-hooks/exhaustive-deps
    const restartMemoized = useCallback(restart, []);

    useEffect(
        () => {
            if (screen === 'phoneConfirm') {
                restartMemoized(Date.now() + (RE_SEND_AFTER_SECONDS * 1000));
            } else {
                pauseMemoized();
            }
        },
        [screen, pauseMemoized, restartMemoized],
    );

I think the problem needs to be solved radically. That is, in the source.

I was solving a similar problem nearby: pbeshai/use-query-params#46

Count up from a given timestamp

Is there any way to count up from a timestamp, i.e useStopwatch with a start timestamp passed to start the count from, or useTimer with a timestamp in the past.

I have tried doing the following, but this immediately expires

const t = new Date();
  t.setSeconds(t.getSeconds() - 600);
  const { hours, minutes, seconds } = useTimer({
    t,
  });

If this isn't available no worries, just wondered if I am missing something obvious. Thanks!

Handling multiple timers

Hello,
First of all thanks a lot for the lib and your continuous work on it


It would be highly valuable for my project to be able to handle a dynamic number of timers (dynamicity making it incompatible with calling useTimer n-times)

The API could look like this:

export function useMultipleTimers(settings: TimerSettings): TimerResult

interface TimerSettings {
    // no expiryTimestamp: it MUST be defined at runtime (start or restart), making start & restart identical functions
    onExpire?: (timerId) => void;
}

interface TimerResult {
    getRemainingTime: (timerId: string) => {
        seconds: number;
        minutes: number;
        hours: number;
        days: number;
    };

    getIsRunning: (timerId: string) => boolean;
    start: (timerId: string, newExpiryTimestamp: Date, autoStart?: boolean) => void;
    pause: (timerId: string) => void;
    resume: (timerId: string) => void;
}

I could give it a go implementing it, but I am looking forward for your opinion beforehand ;)

Thanks!

Widen react-dom peer dependency version requirement

Thanks for making this! When installing this module, we get a warning about an unmet peer dependency on react-dom, as it looks like this module is set to require the exact version of 16.8.0. It seems like this module though works fine with newer versions of react-dom, and I wonder if it should be adjusted to be ^16.8.0 like the react peer depdendency? For reference, react-dom 16.8.0 was released in 02/2019, and they are currently up to 16.13.1.

useTimer pause issue.

useTimer : When we press the pause button and then press the start button after a few seconds of delay, the timer does not start from the paused time.

Not working with SSR

I'm trying to use this with Gatsby.js, but the problem is the UMD wrapper that is generated in the dist folder is referencing window, which breaks the build because window is not defined during SSR.

The best way to fix this/increase compatibility would be to generate builds for multiple targets (see https://medium.com/@kelin2025/so-you-wanna-use-es6-modules-714f48b3a953).

Another, quicker approach might be to include the src/ files in the npm package and reference the src/index.js via the "module" property in package.json

see also:

Timer automatically starts

Is there a way to wait for it to start until I call the start() function or does it always automatically start on initialization?

Live demo

Live demo like CodeSandbox to demonstrate the examples in the documentation for a more practical example?

If accepted, can this be assigned to me?

useStopwatch and useTime args are required

The arguments of useStopwatch and useTime are not optional, so it doesn't match the typescript definition. I would just make the arguments in index.d.ts not optional so it is clear that they are required.

useStopwatch hook is causing continuous rerender

Hi! I'm using this library for making user session time out. For that, I'm using useStopwatch hook.

const { hours, pause, reset } = useStopwatch({ autoStart: true });

But these causes render to the application every second. Is there a better way to achieve it or I'm implementing it wrong?

Update dependency to react v17

Hi, I have a problem when installing this library. it's looks like that this library do not support react v17 yet.

Could not resolve dependency:
npm ERR! peer react@"^16.8.0" from [email protected]
npm ERR! node_modules/react-timer-hook
npm ERR! react-timer-hook@"*" from the root project

Ability to run the timer in smaller intervals (500ms)

Hi,

I had a use case where I needed to run a timer in 1.5 seconds and saw that it was running every second because of
the setInterval that is set to run each 1000ms.

I was wondering whether there is a reason not to support that?
I could work on adding that myself.

Thanks!

Just a question

Does the timer sync across multiple tabs?
My use case is that, in my react app there is a timer which user will set and may leave or close the tab after hitting run button.
My question is will it sync if the user opens up another tab while the timer is running or will it start a new timer?

useStopwatch reset with offsetTimestamp always restarts at 0

Hello! I love the library, thanks so much for making it!

I'm having an issue where calling useStopwatch's reset method with an offsetTimestamp always restarts the hook at 0 (seconds, minutes, hours, days).

In my example onSeek is being called with decimal seconds, much like I am computing currentTime.

export const ExampleComponent = (props: Props): React.ReactElement => {
  const { seconds, minutes, hours, days, isRunning, start, pause, reset } = useStopwatch({
    autoStart: false,
    offsetTimestamp: 0,
  })

  const currentTime = seconds + minutes * 60 + hours * 60 * 60 + days * 60 * 60 * 24
  const setCurrentTime = (newValue: number) => {
    const preserveRunning = isRunning
    reset(newValue - currentTime, preserveRunning)
  }
 ...

  return (
      <Container
        playing={isRunning}
        onPlayingChange={(newPlayValue) => {
          if (newPlayValue) {
            start()
          } else {
            pause()
          }
        }}
        currentTime={currentTime}
        ...
        onSeek={(newValue) => {
          setCurrentTime(newValue)
        }}
      />
  )
}

Thanks in advance for your help!

Start stopwatch from a given time

I need to start the stopwatch from a given time instead of 0.

example: initial start time is given as 5 minutes, then the stopwatch should start counting up from 5 minutes like 5:01, 5:02, 5:03

How can I achieve this functionality?

isPaused Flag

I suggest an isPaused flag like. Currently I need to hold a state besides the timer hook to realize play/pause button.

how to dynamically change offsetTimestamp in useStopwatch

I want to change the offsetTimestamp dynamically to start from speicied value, but once the useStopwatch initialize, it doesn't take updated offsetTimestamp


export default function App() {
  const stopwatchOffset = new Date(); 
  const nn = stopwatchOffset.setSeconds(stopwatchOffset.getSeconds() + 300);
  const [timeDuration, setTimeDuration] = useState<number>(nn);
  return (
    <HeaderTimerHandler timeDuration={timeDuration} setTimeDuration={setTimeDuration} />
  );
}


const HeaderTimerHandler: React.FC<HeaderTimerHandlerProps> = (props) => {
  const { start, hours, minutes, seconds } = useStopwatch({ autoStart: false, offsetTimestamp: props.timeDuration });
  const hidePopover = () => {
    setVisiblity(false);
  }
 return <>{hours:minutes:seconds}</>

useStopwatch not working

useStopwatch lags when the counter is runnings

For testing i followed the below process:

  • I started the useStopwatch in my app, and the regular stop watch on my phone, at the same time.
  • Then i stopped them at the same time.
  • The useStopwatch logged time was 27 minutes.
  • The regular stop watch on my phone's logged time was 1 hour.

I tried this a few more times and the useStopwatch always lagged behind other timers.

Unnecessary re-rendering

For some inexplicable reason, just using the hook to start a timer causes the component in question to re-render once per second. If you use the hook in a more complex component, it becomes a huge problem. At first I thought it might have been because of including the isRunning property from the returned object, but in fact, you don't have to use any of them, and your component will re-render regardless.

The following code snippet exhibits the behavior:

let counter = 0;
const HiddenTimer = props => {
    const {
        expiryTimestamp
    } = props;
    console.log("Will expire at " + expiryTimestamp);
    useTimer({expiryTimestamp, onExpire: () => console.log("Timer has expired"), autoStart: true});
    console.log("Timer is being rendered");

    return (
        <div>Counter at {counter++}</div>
    );
};

Add it to a simple app and you can observe that it is constantly being needlessly re-rendered.

Does this handle on focus window?

Will the timer run correctly in the background if the window is not focused for a long duration?

For eg, if the user keeps the timer tab running and returns to the tab after 1-2 hrs will the timer be consistent?

Handle phones going sleep and tabs in the background

It seems this hook sets the initial time then counts down by second.

   if(isValidExpiryTimestamp(expiryTimestamp) && !intervalRef.current) {
      calculateExpiryDate();
      intervalRef.current = setInterval(() => subtractSecond(), 1000);
    }

But if the phone is asleep of course it can't count down. This means that when it wakes up, the count is behind. The fix could be something like subtracting from the end on each interval rather than depending on the current state.

timer not accurate in mobile

It seems if I lock my phone and get back to the browser, it slows down and after 5 minutes the timer has just counted 20 seconds. How can the timer can be current after the browser becomes active after it being minimized or phone screen locked?

restart Function not working as Expected

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>
)

TypeScript?

Hello! What do you think about rewriting code from JavaScript to TypeScript?
I could probably help with PR.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.