likes
comments
collection
share

关于react中防抖节流的实践

作者站长头像
站长
· 阅读数 21

关于react中防抖节流的实践

该文仅记录我自己在实践中的一些思考,比较啰嗦,不喜勿喷,欢迎讨论。

普通的防抖和节流

以下是工具函数的封装(基础版),实现方法很多,这里仅展示作者常用的。

/**
 * 函数节流
 * @param fn 执行函数 需要防抖的函数也就是你处理逻辑的地方
 * @param time 时间间隔
 * @param params 执行函数需要的参数
 * @returns 
 */
export const throttle = (fn, time, params = {}) => {
  let pre = 0;
  return (e) => {
    const now = new Date().getTime();
    if (now - pre >= time) {
      fn({ e, ...params });
      pre = now;
    }
  };
};
/**
 * 函数防抖
 * @param fn 执行函数 需要防抖的函数也就是你处理逻辑的地方
 * @param time 时间间隔
 * @param params 执行函数需要的参数
 * @returns 
 */
export const debounce = (fn, time, params = {}) => {
  let timer;
  return (e) => {
    clearTimeout(timer);
    timer = setTimeout(() => {
      fn({ e, ...params });
    }, time);
  };
};

实际项目中的应用(该情况不涉及函数组件的refresh)

节流函数生效

关于react中防抖节流的实践 关于react中防抖节流的实践

(setState情况)接着当我们遇到组件refresh的时候,比如在handleClick中去修改一个state

由于触发refresh,每次渲染的时候onClick都对应的是一个新的节流函数 (也就是控制台中每次执行handleClick之后会再一次执行节流函数的初始化)

关于react中防抖节流的实践 关于react中防抖节流的实践

接下来你可能会想到用useCallback来对函数进行缓存,尝试一番,如下图还是不行

关于react中防抖节流的实践

再想一想 破案了!!!如下图handleThrottle内的逻辑等同于节流函数内部的逻辑

这样一看清晰很多,原因就在于节流函数内的pre值,每次都是let pre = 0,这时候你又该想到useRef了对吧, 重点就是要保证函数和计时标准(有的是timer,有的是上一次的时间戳)是保持不变的。 考虑到这步,其实就该想到封装成hook工具。

关于react中防抖节流的实践

封装防抖节流hook

/**
 * 函数节流
 * @param fn 执行函数 需要防抖的函数也就是你处理逻辑的地方
 * @param time 时间间隔
 * @param params 执行函数需要的参数
 * @param dep useCallback的依赖项
 * @returns 
 */
export function useThrottle(fn, delay, params = {}, dep = []) {
  const defaultData: { fn: any; pre: number } = { fn, pre: 0 };
  const { current = { fn: null, pre: 0 } } = useRef(defaultData);
  useEffect(() => {
    current.fn = fn;
  }, [fn]);
  return useCallback((e) => {
    // 用事件间隔做限制
    const now = new Date().getTime();
    const timeDiff = now - (current?.pre || 0);
    if (timeDiff > delay) {
      current.pre = now;
      current.fn?.({ e, ...params });
    }
  }, dep);
}

实际使用

关于react中防抖节流的实践

关于react中防抖节流的实践

感谢阅读