Skip to main content

All hooks

useDebounceValue

Custom hook that returns a debounced version of the provided value, along with a function to update it.


Parameters

  • value: The value to be debounced.
  • delay: The delay in milliseconds before the value is updated.
  • options (optional): Optional configurations for the debouncing behavior.
    • leading (optional): Determines if the debounced function should be invoked on the leading edge of the timeout.
    • trailing (optional): Determines if the debounced function should be invoked on the trailing edge of the timeout.
    • maxWait (optional): The maximum time the debounced function is allowed to be delayed before it's invoked.
    • equalityFn (optional): A custom equality function to compare the current and previous values.

Returns

An array containing the debounced value and the function to update it.

Dependency

This hook is built upon lodash.debounce.

  • useDebounceCallback: useDebounceValue is built on top of useDebounceCallback, it gives more control.

Usage

import { useDebounceValue } from './useDebounceValue'

export default function Component({ defaultValue = 'John' }) {
  const [debouncedValue, setValue] = useDebounceValue(defaultValue, 500)

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

      <input
        type="text"
        defaultValue={defaultValue}
        onChange={event => setValue(event.target.value)}
      />
    </div>
  )
}

API

function useDebounceValue(initialValue: T | () => T, delay?: number, options?: UseDebounceValueOptions<T>): unknown

Custom hook that returns a debounced version of the provided value, along with a function to update it.

Parameters

NameTypeDefault valueDescription
initialValue`T() => T`-
delay?number500The delay in milliseconds before the value is updated.
options?UseDebounceValueOptions<T>-Optional configurations for the debouncing behavior.

Returns

An array containing the debounced value, the function to update it, and whether an update is pending.

Type declaration

UseDebounceValueOptions

Hook options.

NameTypeDescription
equalityFn(left: T, right: T) => booleanA function to determine if the value has changed. Defaults to a function that checks if the value is strictly equal to the previous value.
leadingbooleanDetermines whether the function should be invoked on the leading edge of the timeout.
maxWaitnumberThe maximum time the specified function is allowed to be delayed before it is invoked.
trailingbooleanDetermines whether the function should be invoked on the trailing edge of the timeout.

Hook

import { useCallback, useRef, useState } from 'react'

import type { DebouncedState } from '../useDebounceCallback'
import { useDebounceCallback } from '../useDebounceCallback'

/**
 * Hook options.
 * @template T - The type of the value.
 */
export type UseDebounceValueOptions<T> = {
  /**
   * Determines whether the function should be invoked on the leading edge of the timeout.
   * @default false
   */
  leading?: boolean
  /**
   * Determines whether the function should be invoked on the trailing edge of the timeout.
   * @default false
   */
  trailing?: boolean
  /**
   * The maximum time the specified function is allowed to be delayed before it is invoked.
   */
  maxWait?: number
  /** A function to determine if the value has changed. Defaults to a function that checks if the value is strictly equal to the previous value. */
  equalityFn?: (left: T, right: T) => boolean
}

/**
 * Custom hook that returns a debounced version of the provided value, along with a function to update it.
 * @template T - The type of the value.
 * @param {T | (() => T)} initialValue - The value to be debounced.
 * @param {number} [delay=500] - The delay in milliseconds before the value is updated.
 * @param {object} [options] - Optional configurations for the debouncing behavior.
 * @returns {[T, DebouncedState<(value: T) => void>, boolean]} An array containing the debounced value, the function to update it, and whether an update is pending.
 * @public
 * @see [Documentation](https://usehooks-ts.com/react-hook/use-debounce-value)
 * @example
 * ```tsx
 * const [debouncedValue, updateDebouncedValue, isPending] = useDebounceValue(inputValue, 500);
 * ```
 */
export function useDebounceValue<T>(
  initialValue: T | (() => T),
  delay = 500,
  options?: UseDebounceValueOptions<T>,
): [T, DebouncedState<(value: T) => void>, boolean] {
  const eq = options?.equalityFn ?? ((left: T, right: T) => left === right)
  const unwrappedInitialValue = initialValue instanceof Function ? initialValue() : initialValue
  const [debouncedValue, setDebouncedValue] = useState<T>(unwrappedInitialValue)
  const previousValueRef = useRef<T | undefined>(unwrappedInitialValue)
  const [isPending, setIsPending] = useState(false)

  const internalDebounce = useDebounceCallback(
    (value: T) => {
      setDebouncedValue(value)
      setIsPending(false)
    },
    delay,
    options,
  )

  const updateDebouncedValue = useCallback(
    Object.assign(
      (value: T) => {
        setIsPending(true)
        return internalDebounce(value)
      },
      {
        cancel: () => {
          internalDebounce.cancel()
          setIsPending(false)
        },
        flush: () => internalDebounce.flush(),
        isPending: () => internalDebounce.isPending(),
      },
    ) as DebouncedState<(value: T) => void>,
    [internalDebounce],
  )

  // Update the debounced value if the initial value changes
  if (!eq(previousValueRef.current as T, unwrappedInitialValue)) {
    updateDebouncedValue(unwrappedInitialValue)
    previousValueRef.current = unwrappedInitialValue
  }

  return [debouncedValue, updateDebouncedValue, isPending]
}