A simple countdown implementation. Support increment and decrement.
NEW VERSION: A simple countdown implementation. Accepts countStop(new), countStart (was seconds), intervalMs(was interval) and isIncrement as keys of the call argument. Support increment and decrement. Will stop when at countStop.
Related hooks:
Usage
import { useState } from 'react'
import type { ChangeEvent } from 'react'
import { useCountdown } from './useCountdown'
export default function Component() {
const [intervalValue, setIntervalValue] = useState<number>(1000)
const [count, { startCountdown, stopCountdown, resetCountdown }] = useCountdown({
countStart: 60,
intervalMs: intervalValue,
})
const handleChangeIntervalValue = (event: ChangeEvent<HTMLInputElement>) => {
setIntervalValue(Number(event.target.value))
}
return (
<div>
<p>Count: {count}</p>
<input type="number" value={intervalValue} onChange={handleChangeIntervalValue} />
<button onClick={startCountdown}>start</button>
<button onClick={stopCountdown}>stop</button>
<button onClick={resetCountdown}>reset</button>
</div>
)
}
API
function useCountdown(countdownOptions: CountdownOptions): unknown
Custom hook that manages countdown.
Parameters
| Name | Type | Default value | Description |
|---|---|---|---|
countdownOptions | CountdownOptions | - | The countdown's options. |
Returns
An array containing the countdown's count and its controllers.
Type declaration
CountdownControllers
The countdown's controllers.
| Name | Type | Description |
|---|---|---|
resetCountdown | () => void | Reset the countdown. |
startCountdown | () => void | Start the countdown. |
stopCountdown | () => void | Stop the countdown. |
CountdownOptions
The countdown's options.
| Name | Type | Description |
|---|---|---|
countStart | number | The countdown's starting number, initial value of the returned number. |
countStop | number | The countdown's stopping number. Pass -Infinity to decrease forever. |
intervalMs | number | The countdown's interval, in milliseconds. |
isIncrement | boolean | True if the countdown is increment. |
Hook
import { useCallback } from 'react'
import { useBoolean } from '../useBoolean'
import { useCounter } from '../useCounter'
import { useInterval } from '../useInterval'
/** The countdown's options. */
export type CountdownOptions = {
/** The countdown's starting number, initial value of the returned number. */
countStart: number
/**
* The countdown's interval, in milliseconds.
* @default 1000
*/
intervalMs?: number
/**
* True if the countdown is increment.
* @default false
*/
isIncrement?: boolean
/**
* The countdown's stopping number. Pass `-Infinity` to decrease forever.
* @default 0
*/
countStop?: number
}
/** The countdown's controllers. */
export type CountdownControllers = {
/** Start the countdown. */
startCountdown: () => void
/** Stop the countdown. */
stopCountdown: () => void
/** Reset the countdown. */
resetCountdown: () => void
}
/**
* Custom hook that manages countdown.
* @param {CountdownOptions} countdownOptions - The countdown's options.
* @returns {[number, CountdownControllers]} An array containing the countdown's count and its controllers.
* @public
* @see [Documentation](https://usehooks-ts.com/react-hook/use-countdown)
* @example
* ```tsx
* const [counter, { start, stop, reset }] = useCountdown({
* countStart: 10,
* intervalMs: 1000,
* isIncrement: false,
* });
* ```
*/
export function useCountdown({
countStart,
countStop = 0,
intervalMs = 1000,
isIncrement = false,
}: CountdownOptions): [number, CountdownControllers] {
const {
count,
increment,
decrement,
reset: resetCounter,
} = useCounter(countStart)
/*
* Note: used to control the useInterval
* running: If true, the interval is running
* start: Should set running true to trigger interval
* stop: Should set running false to remove interval.
*/
const {
value: isCountdownRunning,
setTrue: startCountdown,
setFalse: stopCountdown,
} = useBoolean(false)
// Will set running false and reset the seconds to initial value.
const resetCountdown = useCallback(() => {
stopCountdown()
resetCounter()
}, [stopCountdown, resetCounter])
const countdownCallback = useCallback(() => {
if (count === countStop) {
stopCountdown()
return
}
if (isIncrement) {
increment()
} else {
decrement()
}
}, [count, countStop, decrement, increment, isIncrement, stopCountdown])
useInterval(countdownCallback, isCountdownRunning ? intervalMs : null)
return [count, { startCountdown, stopCountdown, resetCountdown }]
}