@kcuf-hook/use-debounced
Version:
React hook - useDebounced/useThrottled.
84 lines (82 loc) • 3.05 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = useDebouncedCallback;
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
var _react = require("react");
var _useIsUnmounted = _interopRequireDefault(require("@kcuf-hook/use-is-unmounted"));
var _util = require("../util");
function useDebouncedCallback(fn, options) {
var refFn = (0, _react.useRef)(fn);
var refArgs = (0, _react.useRef)(null); // 上次调用 `fn` 的参数列表,执行后会被清空
var refTimeCalled = (0, _react.useRef)(0); // 上次调用 `fn` 的时间(但不一定执行)
var refTimeInvoked = (0, _react.useRef)(0); // 上次真正执行 `fn` 的时间
var refTimerId = (0, _react.useRef)(null);
var isUnmounted = (0, _useIsUnmounted.default)();
var _resolveOptions = (0, _util.resolveOptions)(options),
delay = _resolveOptions.delay,
delayMax = _resolveOptions.delayMax,
immediate = _resolveOptions.immediate;
refFn.current = fn; // always fresh
(0, _react.useEffect)(function () {
return function () {
if (refTimerId.current) {
clearTimeout(refTimerId.current);
}
refTimerId.current = null;
};
}, []);
return (0, _react.useMemo)(function () {
function invokeFn() {
var args = refArgs.current;
if (args) {
refArgs.current = null;
refTimeInvoked.current = Date.now();
refFn.current.apply(refFn, (0, _toConsumableArray2.default)(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]);
}