背景
输入框,在输入的过程中搜索匹配的内容下拉框展示。配合change事件搜索匹配结果会导致搜索很频繁。自然而然想到使用防抖避免频繁查询。
防抖不生效
function Com() {
const [schoolValue, setSchoolValue] = useState('')
const debounced = (fn: Function) => {
let timeout: number;
return function () {
let context = this;
let args = arguments;
if (timeout) {
clearTimeout(timeout)
};
timeout = setTimeout(() => {
fn.apply(context, args)
}, 3000)
}
};
const searchSchool = debounced(() => {
console.log('进行搜索操作:--->', schoolValue)
});
useEffect(() => {
searchSchool();
}, [schoolValue]);
return <input value={schoolValue} onChange={e => setSchoolValue(e.target.value)} placeholder='请输入' />
}
由于输入框的value绑定的是schoolValue,所以需要在数据更改的时候(也就是change的时候)需要setSchoolValue,不然会导致输入框不能输入内容。
但是setSchoolValue会导致组件重新render,render之后会导致debounced重新声明,timeout自然也被重新赋值。之前的timeout没有清除,后续一并触发,所以没有达到防抖的效果。
清除之前的timeout
function Com() {
const [schoolValue, setSchoolValue] = useState('')
let timeout: number;
const debounced = (fn: Function) => {
return function () {
let context = this;
let args = arguments;
if (timeout) {
clearTimeout(timeout)
};
timeout = setTimeout(() => {
fn.apply(context, args)
}, 3000)
}
};
const searchSchool = debounced(() => {
console.log('进行搜索操作:--->', schoolValue)
});
useEffect(() => {
searchSchool();
return () => {
clearTimeout(timeout)//清除timeout
};
}, [schoolValue]);
return <input value={schoolValue} onChange={e => setSchoolValue(e.target.value)} placeholder='请输入' />
}
export default Com;
通过ref
function Com() {
const [schoolValue, setSchoolValue] = useState('')
let timeout = useRef<number>();
const debounced = (fn: Function) => {
return function () {
let context = this;
let args = arguments;
if (timeout.current) {
clearTimeout(timeout.current)
};
timeout.current = setTimeout(() => {
fn.apply(context, args)
}, 3000)
}
};
const searchSchool = debounced(() => {
console.log('进行搜索操作:--->', schoolValue)
});
useEffect(() => {
searchSchool();
}, [schoolValue]);
return <input value={schoolValue} onChange={e => setSchoolValue(e.target.value)} placeholder='请输入' />
}
export default Com;
因为在不同的render中ref总是指向同一个引用地址,所有的操作都是在这一个地址上操作的。
自定义 useDebounce
// 定义一个防抖函数
function useDebounce(callback: Function, delay: number) {
const [timer, setTimer] = useState<number>();
return function (...args: any[]) {
clearTimeout(timer);
const newTimer = setTimeout(() => {
callback(...args);
}, delay);
setTimer(newTimer);
};
}
function Com() {
const [schoolValue, setSchoolValue] = useState('')
// 使用防抖函数
const debouncedSearch = useDebounce((value: string) => {
console.log("发送请求:", value);
}, 1000);
useEffect(() => {
debouncedSearch(schoolValue)
}, [schoolValue])
return <input value={schoolValue} onChange={e => setSchoolValue(e.target.value)} placeholder='请输入' />
}
export default Com;