All files / src/utils useDebounceEffect.ts

86.66% Statements 26/30
80% Branches 4/5
100% Functions 1/1
86.66% Lines 26/30

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42  1x       1x     1x 1x 79x 79x   79x 79x 79x 79x   79x 41x 41x       41x 41x     41x   41x 41x 41x 41x 41x 41x   41x 41x 79x 79x  
import type { DependencyList } from "react"
import { useEffect, useRef } from "react"
 
type VoidFn = () => void
 
/**
 * Runs `effectRef.current()` after `delay` ms whenever any of the `deps` change,
 * but cancels/re-schedules if they change again before the delay.
 */
export function useDebounceEffect(effect: VoidFn, delay: number, deps: DependencyList) {
	const callbackRef = useRef<VoidFn>(effect)
	const timeoutRef = useRef<NodeJS.Timeout | null>(null)
 
	// Keep callbackRef current
	useEffect(() => {
		callbackRef.current = effect
	}, [effect])
 
	useEffect(() => {
		// Clear any queued call
		if (timeoutRef.current) {
			clearTimeout(timeoutRef.current)
		}
 
		// Schedule a new call
		timeoutRef.current = setTimeout(() => {
			// always call the *latest* version of effect
			callbackRef.current()
		}, delay)
 
		// Cleanup on unmount or next effect
		return () => {
			if (timeoutRef.current) {
				clearTimeout(timeoutRef.current)
			}
		}
 
		// We want to re‐schedule if any item in `deps` changed,
		// or if `delay` changed.
	}, [delay, ...deps])
}