问题

这有一个简单的防抖函数,短时间内多次触发同一事件,只执行最后一次

function debounce (fn, wait) {
  let timer = null
  return function (...args) {
    if (timer !== null) {
      clearTimeout(timer)
    }
    timer = setTimeout(() => {
      fn(args)
      timer = null
    }, wait)
  }
}

但问题是这个函数在react中使用不生效

export default () => {
  const handleClick = debounce(() => console.log("click fast!"), 1000));
  return (
     <button onClick={handleClick}>click fast!</button>
  );
};

原因就是函数式组件每次渲染,函数都会被重建,导致平时用的 debounce 函数中的timer会重新创建,进而导致防抖失效。

方案一

使用useRef来缓存timer变量

export default function () {
  const click = useDebounce((e: Event) => {
    console.log(e);
  }, 1000)
  
  return (
    <button onClick={click}>按钮</button>
  );
}

function useDebounce(fn: Function, delay: number) {
  const refTimer = useRef<number>();

  return function f(...args: any) {
    if (refTimer.current) {
      clearTimeout(refTimer.current);
    }
    refTimer.current = setTimeout(() => {
      fn(args);
    }, delay);
  }
}

方案二

使用useCallback来缓存函数,只要第二个参数传空数组,那么在组件重新选然时,useCallback中的函数就不会重新创建

export default function DeBounce() {
  const click = useCallback(clickInner(), []);

  function clickInner() {
    let timer: number;
    return function (e: Event) {
      if (timer) {
        clearTimeout(timer);
      }
      timer = setTimeout(() => {
        console.log(e);
      }, 1000);
    }
  }

  return (
    <button onClick={click}>按钮</button>
  );
}
Logo

基于 Vue 的企业级 UI 组件库和中后台系统解决方案,为数万开发者服务。

更多推荐