关于react中防抖节流的实践
关于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)
节流函数生效
(setState情况)接着当我们遇到组件refresh的时候,比如在handleClick中去修改一个state
由于触发refresh,每次渲染的时候onClick都对应的是一个新的节流函数 (也就是控制台中每次执行handleClick之后会再一次执行节流函数的初始化)
接下来你可能会想到用useCallback来对函数进行缓存,尝试一番,如下图还是不行
再想一想 破案了!!!如下图handleThrottle内的逻辑等同于节流函数内部的逻辑
这样一看清晰很多,原因就在于节流函数内的pre值,每次都是let pre = 0,这时候你又该想到useRef了对吧, 重点就是要保证函数和计时标准(有的是timer,有的是上一次的时间戳)是保持不变的。 考虑到这步,其实就该想到封装成hook工具。
封装防抖节流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);
}
实际使用
感谢阅读
转载自:https://juejin.cn/post/7208087678764367927