Custom hook that creates a debounced version of a callback function.


import { useState } from 'react'

import { useDebounceCallback } from 'usehooks-ts'

export default function Component() {
  const [value, setValue] = useState('')

  const debounced = useDebounceCallback(setValue, 500)

  return (
      <p>Debounced value: {value}</p>

        onChange={event => debounced(}


useDebounceCallback<T>(func, delay?, options?): DebouncedState<T>

Custom hook that creates a debounced version of a callback function.

Type parameters

Textends (...args: any) => ReturnType<T>Type of the original callback function.


NameTypeDefault valueDescription
funcTundefinedThe callback function to be debounced.
delaynumber500The delay in milliseconds before the callback is invoked (default is 500 milliseconds).
options?DebounceOptionsundefinedOptions to control the behavior of the debounced function.



A debounced version of the original callback along with control functions.

Type aliases

Ƭ ControlFunctions: Object

Functions to manage a debounced callback.

Type declaration

cancel() => voidCancels pending function invocations.
flush() => voidImmediately invokes pending function invocations.
isPending() => booleanChecks if there are any pending function invocations.

Ƭ DebounceOptions: Object

Configuration options for controlling the behavior of the debounced function.

Type declaration

leading?booleanDetermines whether the function should be invoked on the leading edge of the timeout. Default ts false
maxWait?numberThe maximum time the specified function is allowed to be delayed before it is invoked.
trailing?booleanDetermines whether the function should be invoked on the trailing edge of the timeout. Default ts false

Ƭ DebouncedState<T>: (...args: Parameters<T>) => ReturnType<T> | undefined & ControlFunctions

Represents the state and control functions of a debounced callback. Subsequent calls to the debounced function return the result of the last invocation. Note: If there are no previous invocations, the result will be undefined. Ensure proper handling in your code.

Type parameters

Textends (...args: any) => ReturnType<T>


import { useEffect, useMemo, useRef } from 'react'

import debounce from 'lodash.debounce'

import { useUnmount } from 'usehooks-ts'

type DebounceOptions = {
  leading?: boolean
  trailing?: boolean
  maxWait?: number

type ControlFunctions = {
  cancel: () => void
  flush: () => void
  isPending: () => boolean

export type DebouncedState<T extends (...args: any) => ReturnType<T>> = ((
  ...args: Parameters<T>
) => ReturnType<T> | undefined) &

export function useDebounceCallback<T extends (...args: any) => ReturnType<T>>(
  func: T,
  delay = 500,
  options?: DebounceOptions,
): DebouncedState<T> {
  const debouncedFunc = useRef<ReturnType<typeof debounce>>()

  useUnmount(() => {
    if (debouncedFunc.current) {

  const debounced = useMemo(() => {
    const debouncedFuncInstance = debounce(func, delay, options)

    const wrappedFunc: DebouncedState<T> = (...args: Parameters<T>) => {
      return debouncedFuncInstance(...args)

    wrappedFunc.cancel = () => {

    wrappedFunc.isPending = () => {
      return !!debouncedFunc.current

    wrappedFunc.flush = () => {
      return debouncedFuncInstance.flush()

    return wrappedFunc
  }, [func, delay, options])

  // Update the debounced function ref whenever func, wait, or options change
  useEffect(() => {
    debouncedFunc.current = debounce(func, delay, options)
  }, [func, delay, options])

  return debounced