怎么通过 React Hook 写防抖、节流

3,642 阅读2分钟

有时候,我们需要在 React 组件里,做一些防抖、节流处理。

这篇文章,让我们一起来看看怎么通过 React Hook 形式写防抖、节流。

利用 Lodash 的 Throttle 函数

lodash 的 throttle 函数,可以在固定的时间限制函数执行。

对应实例,我们可以这样写:

import React, { useEffect, useRef, useState } from "react";
import { throttle } from "lodash";

export default function App() {
  const [value, setValue] = useState(0);
  const throttled = useRef(throttle((newValue) => console.log(newValue), 1000));
  
  useEffect(() => throttled.current(value), [value]);
  
  return <button onClick={() => setValue(value + 1)}>{value}</button>;
}

因为 throttle 函数执行间隔是单位是毫秒,所以我们的函数会在 1000 毫秒内只执行一次。

我们利用 useRef 的设置 throttle 可以利用 throttle.current 的形式直接使用。

throttle 会把函数缓存起来,在重新 render 时,我们不会重复创建函数。

然后,我们创建一个 useEffect 并调用函数,当我们点击这个按钮时,我们可以看到 throttled 函数只执行一次。

利用 useCallback 来存储 Throttle

我们可以使用 useCallback 来替换 useRef

对应实例,我们可以这样写:

import React, { useCallback, useEffect, useState } from "react";
import { throttle } from "lodash";

export default function App() {
  const [value, setValue] = useState(0);
  const throttled = useCallback(
    throttle((newValue) => console.log(newValue), 1000),
    []
  );
  
  useEffect(() => throttled(value), [value]);
  
  return <button onClick={() => setValue(value + 1)}>{value}</button>;
}

我们可以通过 useCallbacl 将 throttle 的函数缓存起来,避免 render 时,重复创建。

可以得到上一个例子一样的结果

防抖

防抖函数,意味着我们的代码将被延迟执行。

我们可以自己写一个 hook:

import React, { useCallback, useEffect, useState } from "react";

const useDebouncedEffect = (effect, delay, deps) => {
  const callback = useCallback(effect, deps);
  
  useEffect(() => {
    const handler = setTimeout(() => {
      callback();
    }, delay);
    return () => {
      clearTimeout(handler);
    };
  }, [callback, delay]);
};
export default function App() {
  const [value, setValue] = useState(0);
  
  useDebouncedEffect(() => console.log(value), 1000, [value]);
  
  return <button onClick={() => setValue(value + 1)}>{value}</button>;
}

useDebouncedEffect 是通过在 useEffect 中利用 setTimeout 来执行回调。

我们调用的回调函数,是从传入的 effect。

在组件 redner 时,因为我们是使用 useCallback 缓存了 effect,所以我们不会重复创建函数。

deps 被 useCallback 监听了,所以 deps 发生改变时,函数会重新创建。

setTimeout 返回了一个时间对象,所以在组件卸载时,我们可以利用它清除 setTimeout。

当我们组件卸载时,我们通过 clearTimeout 来清除计时器。

在 App 组件中,我们利用 useDebouncedEffect 来延迟执行我们的函数。

现在,我们点击按钮,直到我们等待 1000 毫秒,函数将会被执行。

总结

看会了吗?看会了,我们可以很轻易的在 React 中使用防抖节流。

核心是函数缓存和延迟执行,函数缓存通过 useCallback 和 uesRef 来实现。

搬运来源:How to use Throttle or Debounce with React Hook