В этой серии статей мы отправимся в путешествие по миру пользовательских хуков 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 секунду, что эффективно предотвращает чрезмерное количество предупреждений при быстром нажатии кнопки.
Комментарии (5)
Caek
28.08.2025 05:55в последних версиях реакта, уже добавили этот хук https://react.dev/reference/react/useDeferredValue
Vitaly_js
28.08.2025 05:55Это не одно и тоже. Если дебоунс используется, что бы не спамить бэк, то useDefferedValue в базовом исполнении не поможет. Т.е. интерфейс будет вести себя как вы хотите, но на фоне будут проходить все запросы к серверу. А обычный дебоунс пропускает запросы только после delay
Vitaly_js
28.08.2025 05:55А вот это все проходило хоть какую-то проверку временем? Подвергалось пристальному рассмотрению перед публикацией?
Я это и про примеры и про решение.
Если идти сверху вниз.
Зачем вам в useDebounce нечто, что вы называете dependencies?
Ну, потому что useTimeount от этого не зависит, а зависит только от callback. А значит если, callback меняется, то все хуки срабатывают. И что это тогда за dependencies, если он не зависим от callback?
А самое забавное, что потом идет пример, который наглядно демонстрирует всю эту ситуацию.
Вы в свой хук отправляете литерал стрелочной функции. И поэтому вообще не имеет значения, что у вас там за массив [count] такой, потому, что литерал в зависимостях будут заставлять выполянться все хуки, куда он прокинут.
И второе, вы проверяли это работает? Потому что на вид, вы неверно сэмулировали useEffect. При выполнении эффекта сначала должна выполняться функции отмены предыдущего эффета, а потом уже функция нового эффекта. А у вас наоборот. При этом clear у вас общая для любого reset. А это значит, что вы устанавливаете новый ресет, и тут же clear его отменяет. Или я где-то упустил мысль?
EdgarAbgaryan
28.08.2025 05:55дебаунсить нужно разные вещи. просто
useDebounce
не покрывает все случаи. у меня в проекте заведено 3 хука:useDebouncedEffect
useDebouncedValue
useDebouncedFunction
aavezel
и тянем useTimeout...