React hook to create a stopwatch functionality.
Add the hook via the CLI:
npx @novajslabs/cli add useStopwatch
Or copy and paste the code into your project:
import { useState, useEffect } from 'react'
const addLeadingZero = (digit: number): string => {
let timeStr = ''
digit % 10 === digit ? (timeStr += `0${digit}`) : (timeStr += `${digit}`)
return timeStr
}
interface Stopwatch {
current: string
isPaused: boolean
isOver: boolean
currentDays: number
currentHours: number
currentMinutes: number
currentSeconds: number
elapsedSeconds: number
pause: () => void
play: () => void
reset: () => void
togglePause: () => void
}
export const useStopwatch = (): Stopwatch => {
const [time, setTime] = useState({
days: 0,
hours: 0,
minutes: 0,
seconds: 0,
})
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 >= 60) {
s = 0
if (m + 1 >= 60) {
m = 0
if (h + 1 >= 24) {
h = 0
d++
} else {
h++
}
} else {
m++
}
} else {
s++
}
return { days: d, hours: h, minutes: m, seconds: s }
})
}, 1000)
return () => clearInterval(interval)
}, [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:
time.days * 86400 + time.hours * 3600 + time.minutes * 60 + time.seconds,
pause: () => setPaused(true),
play: () => setPaused(false),
reset: () => {
setIsOver(false)
setTime({ days: 0, hours: 0, minutes: 0, seconds: 0 })
},
togglePause: () => {
setPaused(!paused)
},
}
}
React 16.8 or higher
- Name
current
- Type
- string
- Description
The current value of the stopwatch.
- Name
isPaused
- Type
- boolean
- Description
Represents whether the stopwatch is paused (true) or not (false).
- Name
isOver
- Type
- boolean
- Description
Represents whether the stopwatch has ended paused (true) or not (false).
- Name
currentDays
- Type
- number
- Description
The current value of days on the stopwatch.
- Name
currentHours
- Type
- number
- Description
The current value of hours on the stopwatch.
- Name
currentMinutes
- Type
- number
- Description
The current value of minutes on the stopwatch.
- Name
currentSeconds
- Type
- number
- Description
The current value of the seconds in the stopwatch.
- Name
elapsedSeconds
- Type
- number
- Description
The number of seconds that have passed since the start of the stopwatch.
- Name
pause
- Type
- function
- Description
Pause the stopwatch.
- Name
play
- Type
- function
- Description
Play the stopwatch.
- Name
reset
- Type
- function
- Description
Reset the stopwatch.
- Name
togglePause
- Type
- function
- Description
Toggle between pausing and playing the stopwatch.
import { useStopwatch } from './hooks/useStopwatch'
const App = () => {
const {
current,
isPaused,
isOver,
currentDays,
currentHours,
currentMinutes,
currentSeconds,
elapsedSeconds,
pause,
play,
reset,
togglePause,
} = useStopwatch()
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>
<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:
- Tracking time elapsed during a coding session in a developer productivity tool
- Creating a stopwatch feature for tracking workout durations in a fitness tracking app