我正在尝试为mui自动完成实现debounce
,但是效果不太好。
我想在inputValue
更改时向服务器发送去抖请求。
我错过什么了吗?
看起来loadData
在每次输入更改时都被触发。只有第一次加载debounce
才起作用。
https://codesandbox.io/s/debounce-not-working-j4ixgg?file=/src/App.js
下面是来自沙箱的代码:
import { useState, useCallback } from "react";
import { Autocomplete, TextField } from "@mui/material";
import { debounce } from "lodash";
import topFilms from "./topFilms";
export default function App() {
const [value, setValue] = useState(null);
const [inputValue, setInputValue] = useState("");
const [options, setOptions] = useState([]);
const loadData = () => {
// sleep(1000)
const filteredOptions = topFilms.filter((f) =>
f.title.includes(inputValue)
);
// This log statement added by Ryan Cogswell to show why it isn't working.
console.log(
`loadData with ${filteredOptions.length} options based on "${inputValue}"`
);
setOptions(filteredOptions);
};
const debouncedLoadData = useCallback(debounce(loadData, 1000), []);
const handleInputChange = (e, v) => {
setInputValue(v);
debouncedLoadData();
};
const handleChange = (e, v) => {
setValue(v);
};
return (
<div className="App">
<Autocomplete
value={value}
inputValue={inputValue}
onChange={handleChange}
onInputChange={handleInputChange}
disablePortal
options={options}
getOptionLabel={(option) => option.title}
isOptionEqualToValue={(option, value) => option.title === value.title}
id="combo-box-demo"
renderInput={(params) => <TextField {...params} label="Movie" />}
/>
</div>
);
}
2条答案
按热度按时间idfiyjo81#
在您的沙箱中,
loadData
成功地去抖,但是它总是使用inputValue === ""
执行,然后匹配所有选项。所有实际的过滤都立即由Autocomplete
组件完成,就像您静态提供了全套选项一样。由于JavaScript闭包的行为,inputValue
始终为空字符串,因为这是创建loadData
去抖版本时的初始值。无论何时创建去抖函数,我建议在顶层声明和定义原始函数和去抖版本,而不是在组件内部。去抖函数所依赖的任何局部变量和状态都可以作为参数传递给函数(例如,在我的代码版本中,将输入值和X1 M5 N1 X函数传递到X1 M6 N1 X)。这避免了由于闭包行为而意外使用过时的值,并消除了对
useCallback
的需要。下面是代码的修改版本,它将
loadData
和debouncedLoadData
移到顶层。(而不是所有数据),以便更容易看到去抖动行为--否则,每当自动完成具有完整的选项集时,过滤将基于自动完成已经有的选项立即发生。2这也更接近真实的代码可能做的事情(即避免为空字符串调用后端)。f8rj6qna2#
tldr: codesandbox link
你可以通过几个钩子一起工作来完成这个任务。首先让我们看看去抖动状态的钩子:
上面的代码接受一个值,然后从钩子返回去抖动的值。useEffect末尾的回调防止了一堆定时器一个接一个地触发。
然后,您的组件可以简化为:
当依赖项
debouncedValue
通过react state business更改时,此处的useEffect将运行。当键入TextField时,控制台应如下所示:App
中的useEffect
为您提供了一个很好的位置来执行对服务器的提取,就像您提到的那样。