如何用Typescript编写自定义React useDebounce Hook

231 阅读3分钟

简介

在过去的一年里,React发布了Hooks,它使我们能够在功能组件中使用状态和其他功能,而不是编写类组件。我们还可以编写自定义钩子,让我们把组件逻辑抽象成可重用的函数。在这篇文章中,我们将使用Typescript编写一个自定义的useDebounce 钩子!

什么是退避?

退避是一种编程技术,它使我们能够推迟执行一个潜在的昂贵的操作,而不是不断地执行它。一个很好的例子是根据用户的输入来过滤大型列表。与其在每个按键上进行过滤,我们可以使用去抖功能,只在用户在几秒钟内没有输入任何东西的情况下应用过滤器。

在下面的截图中,我们显示了一个大的城市列表只有在用户暂停输入一秒钟后才会被过滤。 image.png

我们的自定义钩子应该如何工作?

我们有很多方法可以编写我们的钩子,但让我们把它的使用方法与setState 钩子相对类似。

const [value, setValue] = useState<string>('');

不同的是,我们要。

  1. 指定退避时间
  2. 检索当前值退避值。

所以它应该看起来像这样。

const [debouncedValue, value, setValue] = useDebounce<string>('', 1000);

然后我们可以使用useEffect 钩子,根据debouncedValue 的变化采取一些行动。

const [debouncedValue, value, setValue] = useDebounce<string>('', 1000);

useEffect(() => {
  // Do something with the debounced value
  // e.g., setCities(cities.filter(el => el.name.includes(debouncedValue)))
}, [debouncedValue]);

编写钩子

useDebounce类型

首先,让我们创建我们的useDebounce 函数,并确保我们已经正确定义了它的参数和返回类型。我们要确保我们的钩子接受一个泛型,提供初始值、值和退避值的类型。我们的两个参数,initalValuetime ,将分别由泛型类型和number 类型。最后,我们的函数将返回一个三元素数组。第一个元素(我们公布的值)将是通用类型,第二个元素(我们最新的/当前的值)也是通用类型,最后一个元素将是我们的设置,即React.Dispatch

function useDebounce<T>(
  initialValue: T,
  time: number
): [T, T, React.Dispatch<T>] {}

编写一个没有跳转的版本

我们的钩子需要维护两个状态:最新的/当前的值和退订的值。我们将使用useState 钩子来维护这些状态。为了使现在的版本非常简单,我们将使用useEffect 钩子来确定何时最新值发生变化,而只是立即改变退调值。在未来,我们将处理为这个过程添加延迟的问题。

import { useState, useEffect } from 'react';

function useDebounce<T>(
  initialValue: T,
  time: number
): [T, T, React.Dispatch<T>] {
  const [value, setValue] = useState<T>(initialValue);
  const [debouncedValue, setDebouncedValue] = useState<T>(initialValue);

  useEffect(() => {
    setDebouncedValue(value);
  }, [value]);

  return [debouncedValue, value, setValue];
}

添加退避功能

我们最后可以添加我们的去抖功能。要做到这一点,我们可以在useEffect 中使用一个setTimeout 。这里的关键是从useEffect 中返回一个取消超时的函数。这个函数实质上就是我们的效果的componentWillUnmount 等价物!。

import { useState, useEffect } from 'react';

function useDebounce<T>(
  initialValue: T,
  time: number
): [T, T, React.Dispatch<T>] {
  const [value, setValue] = useState<T>(initialValue);
  const [debouncedValue, setDebouncedValue] = useState<T>(initialValue);

  useEffect(() => {
    const debounce = setTimeout(() => {
      setDebouncedValue(value);
    }, time);
    return () => {
      clearTimeout(debounce);
    };
  }, [value, time]);

  return [debouncedValue, value, setValue];
}

总结

这就是了!我们现在可以使用我们的自定义钩子来完成调试。