useTimer

React hook to create a timer functionality.

import { useState, useEffect } from 'react'

const parseTime = (time: string) => {
  const splitTime = time.split(':')

  const [days, hours, minutes, seconds] = splitTime.map((value) =>
    Number(value),
  )

  return { days, hours, minutes, seconds }
}

const addLeadingZero = (digit: number): string => {
  let timeStr = ''

  digit % 10 === digit ? (timeStr += `0${digit}`) : (timeStr += `${digit}`)

  return timeStr
}

interface Timer {
  current: string
  isPaused: boolean
  isOver: boolean
  currentDays: number
  currentHours: number
  currentMinutes: number
  currentSeconds: number
  elapsedSeconds: number
  remainingSeconds: number
  pause: () => void
  play: () => void
  reset: () => void
  togglePause: () => void
}

export const useTimer = (startTime: string): Timer => {
  const { days, hours, minutes, seconds } = parseTime(startTime)
  const [time, setTime] = useState({ days, hours, minutes, seconds })
  const [paused, setPaused] = useState(false)
  const divider = ':'
  const [isOver, setIsOver] = useState(false)

  useEffect(() => {
    if (paused) {
      return
    }

    const interval = setInterval(() => {
      setTime((prev) => {
        let d = prev.days
        let h = prev.hours
        let m = prev.minutes
        let s = prev.seconds

        if (s - 1 < 0) {
          s = 59
          if (m - 1 < 0) {
            m = 59
            if (h - 1 < 0) {
              h = 23
              if (d - 1 >= 0) {
                d--
              }
            } else {
              h--
            }
          } else {
            m--
          }
        } else {
          s--
        }

        return { days: d, hours: h, minutes: m, seconds: s }
      })
    }, 1000)

    if (
      time.seconds === 0 &&
      time.minutes === 0 &&
      time.hours === 0 &&
      time.days === 0
    ) {
      setIsOver(true)
      clearInterval(interval)
      return
    }

    return () => clearInterval(interval)
  }, [days, hours, minutes, seconds, time, paused])

  return {
    current: `${addLeadingZero(time.days)}${divider}${addLeadingZero(
      time.hours,
    )}${divider}${addLeadingZero(time.minutes)}${divider}${addLeadingZero(
      time.seconds,
    )}`,
    isPaused: paused,
    isOver,
    currentDays: time.days,
    currentHours: time.hours,
    currentMinutes: time.minutes,
    currentSeconds: time.seconds,
    elapsedSeconds:
      days * 86400 +
      hours * 3600 +
      minutes * 60 +
      seconds -
      (time.days * 86400 +
        time.hours * 3600 +
        time.minutes * 60 +
        time.seconds),
    remainingSeconds:
      time.days * 86400 + time.hours * 3600 + time.minutes * 60 + time.seconds,
    pause: () => setPaused(true),
    play: () => setPaused(false),
    reset: () => {
      setIsOver(false)
      setTime({ days, hours, minutes, seconds })
    },
    togglePause: () => {
      setPaused(!paused)
    },
  }
}

React 16.8 or higher

  • Name
    startTime
    Type
    string
    Required
    required
    Description

    Represents the initial value of the timer in the format dd:hh:mm:ss.

  • Name
    current
    Type
    string
    Description

    The current value of the timer.

  • Name
    isPaused
    Type
    boolean
    Description

    Represents whether the timer is paused (true) or not (false).

  • Name
    isOver
    Type
    boolean
    Description

    Represents whether the timer has ended (true) or not (false).

  • Name
    currentDays
    Type
    number
    Description

    The current value of days on the timer.

  • Name
    currentHours
    Type
    number
    Description

    The current value of hours on the timer.

  • Name
    currentMinutes
    Type
    number
    Description

    The current value of minutes on the timer.

  • Name
    currentSeconds
    Type
    number
    Description

    The current value of the seconds in the timer.

  • Name
    elapsedSeconds
    Type
    number
    Description

    The number of seconds that have passed since the start of the timer.

  • Name
    remainingSeconds
    Type
    number
    Description

    The number of seconds left until the stopwatch ends.

  • Name
    pause
    Type
    function
    Description

    Pause the timer.

  • Name
    play
    Type
    function
    Description

    Play the timer.

  • Name
    reset
    Type
    function
    Description

    Reset the timer.

  • Name
    togglePause
    Type
    function
    Description

    Toggle between pausing and playing the timer.

import { useTimer } from './hooks/useTimer'

const App = () => {
  const {
    current,
    isPaused,
    isOver,
    currentDays,
    currentHours,
    currentMinutes,
    currentSeconds,
    elapsedSeconds,
    remainingSeconds,
    pause,
    play,
    reset,
    togglePause,
  } = useTimer('00:00:00:05')

  return (
    <div>
      <p>Counter value: {current}</p>
      <p>Is the counter paused? {isPaused ? 'Yes' : 'No'}</p>
      <p>Has the counter over? {isOver ? 'Yes' : 'No'}</p>
      <p>Current days: {currentDays}</p>
      <p>Current hours: {currentHours}</p>
      <p>Current minutes: {currentMinutes}</p>
      <p>Current seconds: {currentSeconds}</p>
      <p>Elapsed seconds: {elapsedSeconds}</p>
      <p>Remaining seconds: {remainingSeconds}</p>
      <button onClick={pause}>Pause</button>
      <button onClick={play}>Play</button>
      <button onClick={reset}>Reset</button>
      <button onClick={togglePause}>Toggle Pause</button>
    </div>
  )
}

export default App

Here are some use cases where this React hook is useful:

  • Implementing a countdown timer for a time-limited quiz or exam in an online learning platform
  • Creating a countdown clock for tracking time-sensitive tasks or deadlines in a project management tool
  • Developing a timer feature for timing cooking recipes or workouts in a fitness app
  • Adding a countdown timer for promotions or special events in an e-commerce website
  • Integrating a timer functionality for time-bound challenges or activities in a gamified learning platform