在React和TypeScript中使用Lodash debounce的指南

2,586 阅读2分钟

Lodash是一个包含很多优秀实用功能的软件包。例如,Lodash的 debounce函数可以延迟调用一个传入它的函数。在某些情况下,它可以帮助提高性能。

在这篇文章中,我们将使用debounce ,在用户停止键入时搜索一个星球大战的角色:

Lodash debounce with React and TypeScript

照片: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中找到,链接如下

🏃玩转代码