使用useCallback与Lodash debounce仍多次触发?求解决方案
问题原因与修复方案
问题根源
你现在的问题核心在于**useCallback的依赖项是amount**:每次输入框更新amount时,useCallback都会重新生成一个全新的防抖(debounce)函数。也就是说,你每输入一个字符就创建了一个新的防抖实例,之前的防抖函数还没触发就被新的替代,多个防抖实例同时存在,自然会导致多次执行,完全达不到防抖效果。
修复方案
方案一:用useRef持久化防抖函数
把防抖函数存在useRef里,确保整个组件生命周期内复用同一个防抖实例,同时用ref同步最新的amount值,避免闭包捕获旧值。
import { useEffect, useRef } from 'react'; import debounce from 'lodash/debounce'; // 组件内部逻辑 const amountRef = useRef(''); const loadDataRef = useRef(); // 只初始化一次防抖函数 if (!loadDataRef.current) { loadDataRef.current = debounce(() => { const currentAmount = amountRef.current; console.log('called!', currentAmount); // 这里用 currentAmount 发起API请求 }, 1000); } // 同步最新的amount到ref中 useEffect(() => { amountRef.current = amount; }, [amount]); // 触发防抖函数,并在组件卸载/effect更新时取消防抖 useEffect(() => { loadDataRef.current(); return () => loadDataRef.current.cancel(); }, [amount]);
方案二:调整useCallback依赖,避免频繁创建新防抖函数
如果偏好使用useCallback,可以将其依赖置空(只创建一次防抖函数),同时用ref同步amount,确保防抖回调能拿到最新值:
import { useEffect, useCallback, useRef } from 'react'; import debounce from 'lodash/debounce'; // 组件内部逻辑 const amountRef = useRef(''); const loadData = useCallback( debounce(() => { console.log('called!', amountRef.current); // 用 amountRef.current 发起API请求 }, 1000), [] // 依赖为空,仅初始化一次防抖函数 ); useEffect(() => { amountRef.current = amount; loadData(); // 组件卸载/effect更新时取消防抖 return () => loadData.cancel(); }, [amount, loadData]);
关键注意点
- 务必在组件卸载或
effect重新执行时调用cancel(),防止内存泄漏,也避免组件卸载后还触发API请求。 - 用
useRef保存amount是为了规避闭包陷阱:如果防抖函数直接引用amount,会捕获创建时的旧值,无法拿到最新输入的内容。
内容的提问来源于stack exchange,提问作者Mir Stephen
相关产品推荐
相关产品推荐

