概要
デバウンスは、連続するイベント発火を間引き、最後の発火から指定時間が経過したときだけ処理を実行するテクニックです。 検索入力のたびに API を叩くのではなく、入力が止まってから 300ms 後に1回だけ実行するといった用途に使われます。
基本実装
function debounce<T extends unknown[]>(
fn: (...args: T) => void,
delay: number
) {
let timer: ReturnType<typeof setTimeout> | null = null;
return (...args: T) => {
if (timer) clearTimeout(timer);
timer = setTimeout(() => fn(...args), delay);
};
}
React での使い方
コンポーネント内では useCallback + useRef で安全に管理します。
import { useCallback, useRef } from "react";
function SearchInput() {
const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
const handleChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
if (timerRef.current) clearTimeout(timerRef.current);
timerRef.current = setTimeout(() => {
fetchResults(e.target.value);
}, 300);
}, []);
return <input onChange={handleChange} />;
}
throttle との違い
| debounce | throttle | |
|---|---|---|
| 実行タイミング | 最後の発火から N ms 後 | N ms に 1 回 |
| 主な用途 | 検索入力、自動保存 | スクロール、リサイズ |
テスト
jest.useFakeTimers() と jest.advanceTimersByTime() で時間を制御してテストします。
jest.useFakeTimers();
fireEvent.change(input, { target: { value: "hello" } });
jest.advanceTimersByTime(300);
expect(mockFetch).toHaveBeenCalledTimes(1);