必须在组件卸载时清除防抖定时器,否则会导致内存泄漏或报错;react中用useref保存定时器id并在useeffect清理函数中调用cleartimeout,vue3中用onbeforeunmount配合ref实现相同逻辑。

在 React 或 Vue 等现代前端框架中使用防抖函数时,若未在组件卸载(销毁)时清除定时器,会导致 内存泄漏 或 报错(如“Cannot update a component while rendering a different component”)。核心解决思路是:**保存定时器 ID,并在组件卸载前调用 clearTimeout 清除它**。
React 中使用 useRef + useEffect 清理
推荐用 useRef 保存定时器引用,避免闭包中引用过期的 state/props;再在 useEffect 的清理函数中清除:
import { useState, useEffect, useRef } from 'react';
function SearchInput() {
const [query, setQuery] = useState('');
const debounceTimer = useRef(null);
const handleSearch = () => {
// 每次触发先清上一次定时器
if (debounceTimer.current) {
clearTimeout(debounceTimer.current);
}
debounceTimer.current = setTimeout(() => {
console.log('执行搜索:', query);
// 实际请求逻辑...
}, 300);
};
// 输入变化时防抖调用
const handleChange = (e) => {
setQuery(e.target.value);
handleSearch();
};
// 组件卸载时清理定时器
useEffect(() => {
return () => {
if (debounceTimer.current) {
clearTimeout(debounceTimer.current);
}
};
}, []);
return <input value="{query}" onchange="{handleChange}" placeholder="搜索...">;
}
封装可自动清理的防抖 Hook(React)
更工程化的方式是封装一个带清理能力的自定义 Hook,内部管理定时器并返回可取消方法:
function useDebounce(callback, delay) {
const timerRef = useRef(null);
const debounced = useCallback((...args) => {
if (timerRef.current) {
clearTimeout(timerRef.current);
}
timerRef.current = setTimeout(() => {
callback(...args);
}, delay);
}, [callback, delay]);
useEffect(() => {
return () => {
if (timerRef.current) {
clearTimeout(timerRef.current);
}
};
}, []);
return debounced;
}
// 使用示例
function SearchInput() {
const [query, setQuery] = useState('');
const debouncedSearch = useDebounce((q) => {
console.log('搜索关键词:', q);
}, 300);
const handleChange = (e) => {
setQuery(e.target.value);
debouncedSearch(e.target.value);
};
return <input value="{query}" onchange="{handleChange}">;
}
Vue 3 Composition API 中的处理方式
在 setup 或 script setup 中,可用 onBeforeUnmount 钩子清理定时器:
import { ref, onBeforeUnmount } from 'vue';
export default {
setup() {
const timer = ref(null);
const debouncedFn = (fn, delay) => {
return (...args) => {
if (timer.value) clearTimeout(timer.value);
timer.value = setTimeout(() => fn(...args), delay);
};
};
const search = debouncedFn((q) => {
console.log('搜索:', q);
}, 300);
onBeforeUnmount(() => {
if (timer.value) {
clearTimeout(timer.value);
}
});
return () => (
<input oninput="{(e)"> search(e.target.value)}
placeholder="输入搜索..."
/>
);
}
};
关键注意事项
-
不要用普通变量存定时器 ID(如
let timerId = null),因为在闭包或多次渲染中会丢失引用;必须用useRef(React)或ref(Vue)等响应式/持久化容器 - 防抖函数本身不负责清理,清理逻辑必须由组件生命周期接管,这是开发者责任
- 如果防抖函数被多个地方复用(比如全局工具函数),需确保调用方主动管理定时器生命周期,或改用返回
cancel方法的设计 - 服务端渲染(SSR)环境下,
setTimeout在 Node.js 中有效但无意义,建议加typeof window !== 'undefined'判断
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











