方案探索 · Birchline Web 客户端
给搜索加防抖的三种思路
Prompt
在我们的 React 代码库里,给任务过滤输入框做一个带防抖的搜索——给我三种不同的实现方式,并列出各自的权衡。
01组件内联 useEffect + setTimeout
防抖逻辑直接写在持有输入框的组件里。
export function TaskSearch() {
const [draft, setDraft] = useState('');
const [query, setQuery] = useState('');
useEffect(() => {
const id = setTimeout(() => setQuery(draft), 300);
return () => clearTimeout(id);
}, [draft]);
const { data } = useTasks({ search: query });
return (
<input
value={draft}
onChange={(e) => setDraft(e.target.value)}
placeholder="筛选任务…"
/>
);
}
在 devtools 里好单步调试
同一个概念被拆成两份 state
不引入依赖,bundle 不变
延迟常量藏在组件内部,不易调整
Bundle 影响:+0 kb
可测试性:中等
复用度:低
SSR 安全:是
// src/hooks/useDebounce.ts
export function useDebounce<T>(value: T, ms = 300): T {
const [debounced, setDebounced] = useState(value);
useEffect(() => {
const id = setTimeout(() => setDebounced(value), ms);
return () => clearTimeout(id);
}, [value, ms]);
return debounced;
}
// TaskSearch.tsx
const [draft, setDraft] = useState('');
const query = useDebounce(draft, 300);
const { data } = useTasks({ search: query });
一次 import,过滤、命令栏、看板搜索都能复用
多一个文件需要维护和写文档
配合 fake timer,单测非常容易写
泛型 T 让意图略微模糊
延迟时间作为参数显式暴露,方便调
每次按键依然会触发重新渲染
Bundle 影响:+0.2 kb
可测试性:高
复用度:高
SSR 安全:是
03引入小型外部库
引入 use-debounce,值和回调都用它。
import { useDebouncedCallback }
from 'use-debounce';
export function TaskSearch() {
const [query, setQuery] = useState('');
const onChange = useDebouncedCallback(
(next: string) => setQuery(next),
300,
{ leading: false, maxWait: 1000 },
);
const { data } = useTasks({ search: query });
return (
<input
defaultValue=""
onChange={(e) => onChange(e.target.value)}
/>
);
}
leading / trailing / maxWait 都帮你处理好了
新增运行时依赖,需要定期审计和升级
回调形式跳过了中间的重渲染
非受控输入框,和 Birchline 的表单风格不一致
边界情况(unmount、flush、cancel)测试充分
为一个十行能搞定的东西付 ~1.4 kb gzip
Bundle 影响:+1.4 kb
可测试性:高
复用度:高
SSR 安全:是