Lodash是一个包含很多优秀实用功能的软件包。例如,Lodash的 debounce函数可以延迟调用一个传入它的函数。在某些情况下,它可以帮助提高性能。
在这篇文章中,我们将使用debounce ,在用户停止键入时搜索一个星球大战的角色:

照片:Samuel-Elias NadleronUnsplash
一个现有的应用程序
在我们现有的应用程序中,当用户在input 元素中输入标准时,就会向《星球大战》的API发出请求,搜索匹配的角色:
export default function App() {
const [characters, setCharacters] = React.useState<string[]>([]);
async function search(criteria: string) {
const response = await fetch(
`https://swapi.dev/api/people/?search=${criteria}`
);
const body = await response.json();
return body.results.map((result: Character) => result.name);
}
async function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
// 🐌 causes too many requests 😞
setCharacters(await search(e.target.value));
}
return (
<div className="App">
<input
type="search"
placeholder="Enter your search"
onChange={handleChange}
/>
<ul>
{characters.map((character) => (
<li key={character}>{character}</li>
))}
</ul>
</div>
);
}
这个应用程序的问题是,每当用户在input 元素中进行按键时,就会发出搜索请求。理想情况下,我们希望搜索请求只在用户停止输入时发出。我们可以使用Lodash的debounce 函数来实现这一目的。
安装Lodash
npm install lodash
安装整个Lodash,而不是只安装函数(即npm install lodash.debounce ),因为应用程序的捆绑器(如Webpack)会树状摇动Lodash中不在应用程序中使用的一切。
Lodash的核心包中不包含TypeScript类型,所以我们单独安装这些类型:
npm install @types/lodash
从Lodash导入debounce
debounce 是 包中的一个命名出口,所以我们按如下方式导入它lodash:
import { debounce } from "lodash"
使用debounce--第一次尝试
我们使用debounce ,在300毫秒后调用search :
async function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
debounce(async () => {
// 😕 debounced function never called
setCharacters(await search(e.target.value));
}, 300);
}
因此,从理论上讲,搜索应该在用户停止输入后300毫秒内被调用。
但这个实现并不奏效--搜索功能从未被调用。😕
它不能工作,因为当用户输入下一个字符时,去抖功能就会丢失,而handleChange ,再次被调用。
使用debounce--第二次尝试
我们可以在handleChange 之外提升debounced函数来解决这个问题:
const debouncedSearch = debounce(async (criteria) => {
setCharacters(await search(criteria));
}, 300);
async function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
debouncedSearch(e.target.value);
}
这很好用,但还有一个更有效的方法。
使用debounce--性能更强的方法
目前,每次渲染时都会创建一个新版本的debouncedSearch 。我们可以使用ReactsuseRef 来存储跨渲染的debounced函数:
const debouncedSearch = React.useRef(
debounce(async (criteria) => {
setCharacters(await search(criteria));
}, 300)
).current;
很好!😊
清理工作
当组件解除挂载时,搜索请求可能仍在进行中。在这种情况下,当characters 状态被设置时,会出现错误。
我们可以使用useEffect 钩子来取消debounced函数来解决这个问题。debounce 句柄有一个方便的cancel 方法,我们可以用它来做这件事:
React.useEffect(() => {
return () => {
debouncedSearch.cancel();
};
}, [debouncedSearch]);
这篇文章的代码可以在Codesandbox中找到,链接如下