Skip to content

Instantly share code, notes, and snippets.

@theer1k
Created August 18, 2022 01:05
Show Gist options
  • Save theer1k/3fb24814f33c8803e5bcb772ef5e8222 to your computer and use it in GitHub Desktop.
Save theer1k/3fb24814f33c8803e5bcb772ef5e8222 to your computer and use it in GitHub Desktop.
useThrottledValue
import {
useCallback, useEffect, useRef, useState,
} from 'react'
const DEFAULT_THROTTLE_MS = 3000
const getRemainingTime = (lastTriggeredTime: number, throttleMs: number) => {
const elapsedTime = Date.now() - lastTriggeredTime
const remainingTime = throttleMs - elapsedTime
return (remainingTime < 0) ? 0 : remainingTime
}
export type useThrottledValueProps<T> = {
value: T
throttleMs?: number
}
const useThrottledValue = <T, >({
value,
throttleMs = DEFAULT_THROTTLE_MS,
}: useThrottledValueProps<T>) => {
const [throttledValue, setThrottledValue] = useState<T>(value)
const lastTriggered = useRef<number>(Date.now())
const timeoutRef = useRef<NodeJS.Timeout|null>(null)
const cancel = useCallback(() => {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current)
timeoutRef.current = null
}
}, [])
useEffect(() => {
let remainingTime = getRemainingTime(lastTriggered.current, throttleMs)
if (remainingTime === 0) {
lastTriggered.current = Date.now()
setThrottledValue(value)
cancel()
} else if (!timeoutRef.current) {
timeoutRef.current = setTimeout(() => {
remainingTime = getRemainingTime(lastTriggered.current, throttleMs)
if (remainingTime === 0) {
lastTriggered.current = Date.now()
setThrottledValue(value)
cancel()
}
}, remainingTime)
}
return cancel
}, [cancel, throttleMs, value])
return throttledValue
}
export default useThrottledValue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment