如何在 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,并返回一个元组,便于解构使用。

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

昵称:
邮箱:
内容: