防抖(debounce): 将多次高频操作优化为只在最后一次执行,通常使用的场景是:用户连续输入,只需要在输入结束后做一次校验即可,比如input搜索,校验
- lodash
import { debounce } from "lodash";
const handleChange = debounce(() => {
// send ajax
}, 500)
- useDebounce自定义hook
import { useCallback, useEffect, useRef } from "react";
const useTimeoutFn = (fn, ms) => {
const ready = useRef(false);
const timeout = useRef();
const callback = useRef(fn);
const isReady = useCallback(() => ready.current, []);
const set = useCallback(() => {
ready.current = false;
timeout.current && clearTimeout(timeout.current);
timeout.current = setTimeout(() => {
ready.current = true;
callback.current();
}, ms);
}, [ms]);
const clear = useCallback(() => {
ready.current = null;
timeout.current && clearTimeout(timeout.current);
}, []);
useEffect(() => {
set();
return clear;
}, [ms, clear, set]);
return [isReady, set, clear];
};
const useDebounce = (fn, ms = 0, deps = []) => {
const [isReady, reset, clear] = useTimeoutFn(fn, ms);
useEffect(reset, deps);
};
组件中使用:
const Input = () => {
const [value, setValue] = useState();
const handleChange = (e) => setValue(e.target.value);
useDebounce(
() => {
// send ajax todo
},
400,
[value]
);
return <input value={value} onChange={handleChange} />;
};
节流(throttle):每隔一段时间执行一次,也就是降低频率,将高频操作优化成低频操作。通常使用场景: 滚动条事件,窗口resize事件,通常每隔100-500ms执行一次
- useThrottle自定义hook
import React, { useCallback, useEffect, useRef } from "react";
const useTimeoutFn = (fn, ms) => {
const ready = useRef(false);
const timeout = useRef();
const callback = useRef(fn);
const isReady = useCallback(() => ready.current, []);
const setThrottle = useCallback(() => {
ready.current = false;
if (!timeout.current) {
timeout.current = true;
timeout.current = setTimeout(() => {
ready.current = true;
timeout.current = null;
callback.current();
}, ms);
}
}, [ms]);
const clearThrottle = useCallback(() => {
ready.current = null;
timeout.current && clearTimeout(timeout.current);
}, []);
useEffect(() => {
setThrottle();
return clearThrottle;
}, [ms, setThrottle, clearThrottle]);
return { isReady, setThrottle, clearThrottle };
};
const useThrottle = (fn, ms = 0, deps = []) => {
const { setThrottle } = useThrottleTimeoutFn(fn, ms);
useEffect(setThrottle, deps);
};
在组件中使用
useThrottle(
() => {
console.log(new Date().getSeconds());
},
1000,
[value]
);