如何在 React 中实现一个可复用的防抖(debounce)自定义 Hook?
如何在 React 中实现一个可复用的防抖(debounce)自定义 Hook?
回答:
可以使用 useCallback 和 useRef 创建一个防抖 Hook,例如:
import { useCallback, useRef } from 'react';
function useDebounce(callback: (...args: any[]) => void, delay: number) {
  const timeoutRef = useRef<NodeJS.Timeout | null>(null);
  const debouncedCallback = useCallback((...args: any[]) => {
    if (timeoutRef.current) {
      clearTimeout(timeoutRef.current);
    }
    timeoutRef.current = setTimeout(() => {
      callback(...args);
    }, delay);
  }, [callback, delay]);
  // 可选:提供取消防抖的方法
  const cancel = useCallback(() => {
    if (timeoutRef.current) {
      clearTimeout(timeoutRef.current);
      timeoutRef.current = null;
    }
  }, []);
  return [debouncedCallback, cancel] as const;
}
使用示例:
function SearchInput() {
  const [query, setQuery] = useState('');
  const handleSearch = useCallback((value: string) => {
    console.log('搜索:', value);
  }, []);
  const [debouncedSearch, cancelSearch] = useDebounce(handleSearch, 500);
  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const value = e.target.value;
    setQuery(value);
    debouncedSearch(value);
  };
  return <input value={query} onChange={handleChange} />;
}
解析:
- 防抖的核心是延迟执行函数,如果在延迟期间再次触发,则重置计时器。
- 使用 useRef 保存定时器 ID,避免在组件重新渲染时丢失引用。
- useCallback 确保返回的防抖函数在依赖不变时保持引用一致,避免不必要的子组件重新渲染。
- 提供 cancel 方法可以在组件卸载或特定场景(如用户取消输入)时清除未执行的定时器,防止内存泄漏或无效操作。
- 此 Hook 兼容 TypeScript,并返回一个元组,便于解构使用。

发表评论 (审核通过后显示评论):