@kcuf-hook/use-debounced
Version:
React hook - useDebounced/useThrottled.
78 lines (77 loc) • 2.75 kB
JavaScript
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
import { useRef, useMemo, useEffect } from 'react';
import useIsUnmounted from '@kcuf-hook/use-is-unmounted';
import { resolveOptions } from '../util';
export default function useDebouncedCallback(fn, options) {
var refFn = useRef(fn);
var refArgs = useRef(null); // 上次调用 `fn` 的参数列表,执行后会被清空
var refTimeCalled = useRef(0); // 上次调用 `fn` 的时间(但不一定执行)
var refTimeInvoked = useRef(0); // 上次真正执行 `fn` 的时间
var refTimerId = useRef(null);
var isUnmounted = useIsUnmounted();
var _resolveOptions = resolveOptions(options),
delay = _resolveOptions.delay,
delayMax = _resolveOptions.delayMax,
immediate = _resolveOptions.immediate;
refFn.current = fn; // always fresh
useEffect(function () {
return function () {
if (refTimerId.current) {
clearTimeout(refTimerId.current);
}
refTimerId.current = null;
};
}, []);
return useMemo(function () {
function invokeFn() {
var args = refArgs.current;
if (args) {
refArgs.current = null;
refTimeInvoked.current = Date.now();
refFn.current.apply(refFn, _toConsumableArray(args));
}
}
function startTimer(pendingFunc, wait) {
if (refTimerId.current) {
clearTimeout(refTimerId.current);
}
refTimerId.current = setTimeout(pendingFunc, wait);
}
function timerExpired() {
if (isUnmounted()) {
return;
}
if (Date.now() - refTimeCalled.current >= delay) {
refTimerId.current = null;
invokeFn();
return;
}
var time = Date.now();
var timeSinceLastCall = time - refTimeCalled.current;
var timeSinceLastInvoke = time - refTimeInvoked.current;
var timeWaiting = delay - timeSinceLastCall;
var remainingWait = delayMax >= delay ? Math.min(timeWaiting, delayMax - timeSinceLastInvoke) : timeWaiting;
startTimer(timerExpired, remainingWait);
}
function callFn() {
var time = Date.now();
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
refArgs.current = args;
refTimeCalled.current = time;
if (immediate && !refTimerId.current) {
invokeFn();
}
if (delayMax >= delay && time - refTimeInvoked.current >= delayMax) {
invokeFn();
startTimer(timerExpired, delay);
}
if (!refTimerId.current) {
startTimer(timerExpired, delay);
}
}
return callFn;
}, [delay, delayMax, immediate, isUnmounted]);
}
//# sourceMappingURL=use-debounced-callback.js.map