React中修改state导致lodash的debounce防抖功能失效该如何解决?
问题原因
你的防抖逻辑失效的核心原因是每次组件重渲染都会生成全新的防抖函数实例:
- 你把
debounced_search定义在了组件函数体内部,当你调用setInput更新状态时,会触发组件重渲染,整个Searchbar函数会重新执行一遍 - 重渲染时会重新创建一个新的
search函数和新的debounced_search防抖实例,之前输入触发的防抖计时器直接被废弃,相当于每次输入都触发了一次全新的防抖逻辑,自然就没有延迟生效的效果了。
解决方案
你需要让防抖函数在组件多次重渲染之间保持同一个引用,不要每次渲染都重新生成,常用实现方式如下:
方法1:用useRef保存防抖实例(最稳妥)
useRef存储的值在组件整个生命周期内不会随重渲染变更,刚好适合存防抖实例,同时需要在组件卸载时手动取消防抖,避免内存泄漏:
import React from 'react' import Autocomplete from '@mui/material/Autocomplete'; import { TextField } from '@mui/material'; import debounce from 'lodash/debounce'; function Searchbar() { const [options, setOptions] = React.useState([]); const [input, setInput] = React.useState(""); // 用useRef存储防抖实例,保证重渲染时引用不变 const debouncedSearchRef = React.useRef( debounce((event, newInputValue) => { console.log("Debounced Called") // 这里放置你的API请求逻辑 }, 500) ) // 组件卸载时取消防抖,清理计时器 React.useEffect(() => { return () => { debouncedSearchRef.current.cancel() } }, []) return (<Autocomplete id="free-solo" freeSolo renderInput={(params) => <TextField {...params} label="Test" />} inputValue={input} options={options} onInputChange={function (event, newInputValue) { // 调用ref中存储的稳定防抖实例 debouncedSearchRef.current(event, newInputValue); setInput(newInputValue); console.log("Input Changed") }} />) } export default Searchbar
方法2:用useCallback包裹防抖函数
如果依赖项为空数组,useCallback也可以保证函数引用稳定,效果和useRef一致:
const debounced_search = React.useCallback( debounce((event, newInputValue) => { console.log("Debounced Called") }, 500), [] // 空依赖保证只初始化一次 )
注意同样需要在useEffect的清理函数中调用debounced_search.cancel()处理卸载逻辑。
内容的提问来源于stack exchange,提问作者pask
相关产品推荐
相关产品推荐

