В этой серии статей мы отправимся в путешествие по миру пользовательских хуков React, открывая для себя их огромный потенциал для улучшения ваших проектов разработки. Сегодня мы сосредоточимся на хуке useDebounce, одном из многих тщательно разработанных хуков, доступных в коллекции пользовательских хуков React.

Github: https://github.com/sergeyleschev/react-custom-hooks

import { useEffect } from "react"
import useTimeout from "../useTimeout/useTimeout"

export default function useDebounce(callback, delay, dependencies) {
    const { reset, clear } = useTimeout(callback, delay)
    useEffect(reset, [...dependencies, reset])
    useEffect(clear, [])
}

Хук useDebounce использует хук useTimeout для внутренней задержки выполнения функции обратного вызова до истечения заданного времени задержки. Таким образом, предотвращаются частые обновления, вызванные быстрыми изменениями ввода или повторяющимися событиями, что обеспечивает более плавное взаимодействие и снижает потребление ресурсов.

Одним из главных преимуществ useDebounce является его простота и гибкость. Заключив свою функцию обратного вызова, длительность задержки и любые зависимости в этот пользовательский хук, вы можете без особых усилий реализовать debounce, не загромождая код компонента. Хук управляет тайм-аутом и удаляет его при необходимости, гарантируя, что обратный вызов запускается только после указанной задержки и с учетом последних зависимостей.

Где вы можете использовать useDebounce? Возможности безграничны! Этот настраиваемый механизм особенно полезен в сценариях, где вам нужно обрабатывать вводимые пользователем данные, такие как строки поиска или поля формы, и где вы хотите отложить выполнение действия до тех пор, пока пользователь не закончит вводить текст или взаимодействовать с пользователем. Это также полезно для оптимизации сетевых запросов, гарантируя, что запросы будут отправляться только после того, как пользователь перестанет печатать или выбирать параметры.

import { useState } from "react"
import useDebounce from "./useDebounce"

export default function DebounceComponent() {
    const [count, setCount] = useState(10)
    useDebounce(() => alert(count), 1000, [count])
    return (
        <div>
            <div>{count}</div>
            <button onClick={() => setCount(c => c + 1)}>Increment</button>
        </div>
    )
}

В приведенном выше примере мы демонстрируем возможности useDebounce, реализуя простой компонент счетчика под названием DebounceComponent. Каждый раз, когда пользователь нажимает кнопку «Увеличить», состояние счетчика обновляется. Однако вместо немедленного оповещения о значении count мы отключаем функцию оповещения с помощью useDebounce. Значение count будет отображаться с задержкой в 1 секунду, что эффективно предотвращает чрезмерное количество предупреждений при быстром нажатии кнопки.

Full Version | React Custom Hooks

Комментарии (5)


  1. aavezel
    28.08.2025 05:55

    и тянем useTimeout...


  1. Caek
    28.08.2025 05:55

    в последних версиях реакта, уже добавили этот хук https://react.dev/reference/react/useDeferredValue


    1. Vitaly_js
      28.08.2025 05:55

      Это не одно и тоже. Если дебоунс используется, что бы не спамить бэк, то useDefferedValue в базовом исполнении не поможет. Т.е. интерфейс будет вести себя как вы хотите, но на фоне будут проходить все запросы к серверу. А обычный дебоунс пропускает запросы только после delay


  1. Vitaly_js
    28.08.2025 05:55

    А вот это все проходило хоть какую-то проверку временем? Подвергалось пристальному рассмотрению перед публикацией?

    Я это и про примеры и про решение.

    Если идти сверху вниз.

    Зачем вам в useDebounce нечто, что вы называете dependencies?

    Ну, потому что useTimeount от этого не зависит, а зависит только от callback. А значит если, callback меняется, то все хуки срабатывают. И что это тогда за dependencies, если он не зависим от callback?

    А самое забавное, что потом идет пример, который наглядно демонстрирует всю эту ситуацию.

    Вы в свой хук отправляете литерал стрелочной функции. И поэтому вообще не имеет значения, что у вас там за массив [count] такой, потому, что литерал в зависимостях будут заставлять выполянться все хуки, куда он прокинут.

    И второе, вы проверяли это работает? Потому что на вид, вы неверно сэмулировали useEffect. При выполнении эффекта сначала должна выполняться функции отмены предыдущего эффета, а потом уже функция нового эффекта. А у вас наоборот. При этом clear у вас общая для любого reset. А это значит, что вы устанавливаете новый ресет, и тут же clear его отменяет. Или я где-то упустил мысль?


  1. EdgarAbgaryan
    28.08.2025 05:55

    дебаунсить нужно разные вещи. просто useDebounce не покрывает все случаи. у меня в проекте заведено 3 хука:

    • useDebouncedEffect

    • useDebouncedValue

    • useDebouncedFunction