You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

554 lines
16 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

"use strict";
var __assign = this && this.__assign || function () {
__assign = Object.assign || function (t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) {
if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
}
}
return t;
};
return __assign.apply(this, arguments);
};
var __read = this && this.__read || function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o),
r,
ar = [],
e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) {
ar.push(r.value);
}
} catch (error) {
e = {
error: error
};
} finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
} finally {
if (e) throw e.error;
}
}
return ar;
};
var __spread = this && this.__spread || function () {
for (var ar = [], i = 0; i < arguments.length; i++) {
ar = ar.concat(__read(arguments[i]));
}
return ar;
};
var __importDefault = this && this.__importDefault || function (mod) {
return mod && mod.__esModule ? mod : {
"default": mod
};
};
Object.defineProperty(exports, "__esModule", {
value: true
});
var lodash_debounce_1 = __importDefault(require("lodash.debounce"));
var lodash_throttle_1 = __importDefault(require("lodash.throttle"));
var react_1 = require("react");
var utils_1 = require("./utils");
var cache_1 = require("./utils/cache");
var limit_1 = __importDefault(require("./utils/limit"));
var usePersistFn_1 = __importDefault(require("./utils/usePersistFn"));
var useUpdateEffect_1 = __importDefault(require("./utils/useUpdateEffect"));
var windowFocus_1 = __importDefault(require("./utils/windowFocus"));
var windowVisible_1 = __importDefault(require("./utils/windowVisible"));
var DEFAULT_KEY = 'AHOOKS_USE_REQUEST_DEFAULT_KEY';
var Fetch =
/** @class */
function () {
function Fetch(service, config, subscribe, initState) {
// 请求时序
this.count = 0; // 是否卸载
this.unmountedFlag = false; // visible 后,是否继续轮询
this.pollingWhenVisibleFlag = false;
this.pollingTimer = undefined;
this.loadingDelayTimer = undefined;
this.unsubscribe = [];
this.that = this;
this.state = {
loading: false,
params: [],
data: undefined,
error: undefined,
run: this.run.bind(this.that),
mutate: this.mutate.bind(this.that),
refresh: this.refresh.bind(this.that),
cancel: this.cancel.bind(this.that),
unmount: this.unmount.bind(this.that)
};
this.service = service;
this.config = config;
this.subscribe = subscribe;
if (initState) {
this.state = __assign(__assign({}, this.state), initState);
}
this.debounceRun = this.config.debounceInterval ? lodash_debounce_1["default"](this._run, this.config.debounceInterval) : undefined;
this.throttleRun = this.config.throttleInterval ? lodash_throttle_1["default"](this._run, this.config.throttleInterval) : undefined;
this.limitRefresh = limit_1["default"](this.refresh.bind(this), this.config.focusTimespan);
if (this.config.pollingInterval) {
this.unsubscribe.push(windowVisible_1["default"](this.rePolling.bind(this)));
}
if (this.config.refreshOnWindowFocus) {
this.unsubscribe.push(windowFocus_1["default"](this.limitRefresh.bind(this)));
}
}
Fetch.prototype.setState = function (s) {
if (s === void 0) {
s = {};
}
this.state = __assign(__assign({}, this.state), s);
this.subscribe(this.state);
};
Fetch.prototype._run = function () {
var _this = this;
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
} // 取消已有定时器
if (this.pollingTimer) {
clearTimeout(this.pollingTimer);
} // 取消 loadingDelayTimer
if (this.loadingDelayTimer) {
clearTimeout(this.loadingDelayTimer);
}
this.count += 1; // 闭包存储当次请求的 count
var currentCount = this.count;
this.setState({
loading: !this.config.loadingDelay,
params: args
});
if (this.config.loadingDelay) {
this.loadingDelayTimer = setTimeout(function () {
_this.setState({
loading: true
});
}, this.config.loadingDelay);
}
return this.service.apply(this, __spread(args)).then(function (res) {
if (!_this.unmountedFlag && currentCount === _this.count) {
if (_this.loadingDelayTimer) {
clearTimeout(_this.loadingDelayTimer);
}
var formattedResult = _this.config.formatResult ? _this.config.formatResult(res) : res;
_this.setState({
data: formattedResult,
error: undefined,
loading: false
});
if (_this.config.onSuccess) {
_this.config.onSuccess(formattedResult, args);
}
return formattedResult;
}
})["catch"](function (error) {
if (!_this.unmountedFlag && currentCount === _this.count) {
if (_this.loadingDelayTimer) {
clearTimeout(_this.loadingDelayTimer);
}
_this.setState({
data: undefined,
error: error,
loading: false
});
if (_this.config.onError) {
_this.config.onError(error, args);
} // If throwOnError, user should catch the error self,
// or the page will crash
if (_this.config.throwOnError) {
throw error;
}
console.error(error); // eslint-disable-next-line prefer-promise-reject-errors
return Promise.reject('useRequest has caught the exception, if you need to handle the exception yourself, you can set options.throwOnError to true.');
}
})["finally"](function () {
if (!_this.unmountedFlag && currentCount === _this.count) {
if (_this.config.pollingInterval) {
// 如果屏幕隐藏,并且 !pollingWhenHidden, 则停止轮询,并记录 flag等 visible 时,继续轮询
if (!utils_1.isDocumentVisible() && !_this.config.pollingWhenHidden) {
_this.pollingWhenVisibleFlag = true;
return;
}
_this.pollingTimer = setTimeout(function () {
_this._run.apply(_this, __spread(args));
}, _this.config.pollingInterval);
}
}
});
};
Fetch.prototype.run = function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
if (this.debounceRun) {
this.debounceRun.apply(this, __spread(args)); // TODO 如果 options 存在 debounceInterval或 throttleInterval则 run 和 refresh 不会返回 Promise。 带类型需要修复后,此处变成 return;。
return Promise.resolve(null);
}
if (this.throttleRun) {
this.throttleRun.apply(this, __spread(args));
return Promise.resolve(null);
}
return this._run.apply(this, __spread(args));
};
Fetch.prototype.cancel = function () {
if (this.debounceRun) {
this.debounceRun.cancel();
}
if (this.throttleRun) {
this.throttleRun.cancel();
}
if (this.loadingDelayTimer) {
clearTimeout(this.loadingDelayTimer);
}
if (this.pollingTimer) {
clearTimeout(this.pollingTimer);
}
this.pollingWhenVisibleFlag = false;
this.count += 1;
this.setState({
loading: false
});
};
Fetch.prototype.refresh = function () {
return this.run.apply(this, __spread(this.state.params));
};
Fetch.prototype.rePolling = function () {
if (this.pollingWhenVisibleFlag) {
this.pollingWhenVisibleFlag = false;
this.refresh();
}
};
Fetch.prototype.mutate = function (data) {
if (typeof data === 'function') {
this.setState({
// eslint-disable-next-line react/no-access-state-in-setstate
data: data(this.state.data) || {}
});
} else {
this.setState({
data: data
});
}
};
Fetch.prototype.unmount = function () {
this.unmountedFlag = true;
this.cancel();
this.unsubscribe.forEach(function (s) {
s();
});
};
return Fetch;
}();
function useAsync(service, options) {
var _options = options || {};
var _a = _options.refreshDeps,
refreshDeps = _a === void 0 ? [] : _a,
_b = _options.manual,
manual = _b === void 0 ? false : _b,
_c = _options.onSuccess,
onSuccess = _c === void 0 ? function () {} : _c,
_d = _options.onError,
onError = _d === void 0 ? function () {} : _d,
_e = _options.defaultLoading,
defaultLoading = _e === void 0 ? false : _e,
loadingDelay = _options.loadingDelay,
_f = _options.pollingInterval,
pollingInterval = _f === void 0 ? 0 : _f,
_g = _options.pollingWhenHidden,
pollingWhenHidden = _g === void 0 ? true : _g,
_h = _options.defaultParams,
defaultParams = _h === void 0 ? [] : _h,
_j = _options.refreshOnWindowFocus,
refreshOnWindowFocus = _j === void 0 ? false : _j,
_k = _options.focusTimespan,
focusTimespan = _k === void 0 ? 5000 : _k,
fetchKey = _options.fetchKey,
cacheKey = _options.cacheKey,
_l = _options.cacheTime,
cacheTime = _l === void 0 ? 5 * 60 * 1000 : _l,
_m = _options.staleTime,
staleTime = _m === void 0 ? 0 : _m,
debounceInterval = _options.debounceInterval,
throttleInterval = _options.throttleInterval,
initialData = _options.initialData,
_o = _options.ready,
ready = _o === void 0 ? true : _o,
_p = _options.throwOnError,
throwOnError = _p === void 0 ? false : _p;
var newstFetchKey = react_1.useRef(DEFAULT_KEY); // 持久化一些函数
var servicePersist = usePersistFn_1["default"](service);
var onSuccessPersist = usePersistFn_1["default"](onSuccess);
var onErrorPersist = usePersistFn_1["default"](onError);
var fetchKeyPersist = usePersistFn_1["default"](fetchKey);
var formatResult;
if ('formatResult' in _options) {
// eslint-disable-next-line prefer-destructuring
formatResult = _options.formatResult;
}
var formatResultPersist = usePersistFn_1["default"](formatResult);
var config = {
formatResult: formatResultPersist,
onSuccess: onSuccessPersist,
onError: onErrorPersist,
loadingDelay: loadingDelay,
pollingInterval: pollingInterval,
pollingWhenHidden: pollingWhenHidden,
refreshOnWindowFocus: refreshOnWindowFocus,
focusTimespan: focusTimespan,
debounceInterval: debounceInterval,
throttleInterval: throttleInterval,
throwOnError: throwOnError
};
var subscribe = usePersistFn_1["default"](function (key, data) {
setFetches(function (s) {
// eslint-disable-next-line no-param-reassign
s[key] = data;
return __assign({}, s);
});
});
var _q = __read(react_1.useState(function () {
var _a; // 如果有 缓存,则从缓存中读数据
if (cacheKey) {
var cacheData_1 = (_a = cache_1.getCache(cacheKey)) === null || _a === void 0 ? void 0 : _a.data;
if (cacheData_1) {
newstFetchKey.current = cacheData_1.newstFetchKey;
/* 使用 initState, 重新 new Fetch */
var newFetches_1 = {};
Object.keys(cacheData_1.fetches).forEach(function (key) {
var cacheFetch = cacheData_1.fetches[key];
var newFetch = new Fetch(servicePersist, config, subscribe.bind(null, key), {
loading: cacheFetch.loading,
params: cacheFetch.params,
data: cacheFetch.data,
error: cacheFetch.error
});
newFetches_1[key] = newFetch.state;
});
return newFetches_1;
}
}
return [];
}), 2),
fetches = _q[0],
setFetches = _q[1];
var fetchesRef = react_1.useRef(fetches);
fetchesRef.current = fetches;
var readyMemoryParams = react_1.useRef();
var run = react_1.useCallback(function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
if (!ready) {
// 没有 ready, 记录请求参数,等 ready 后,发起请求用
readyMemoryParams.current = args;
return;
}
if (fetchKeyPersist) {
var key = fetchKeyPersist.apply(void 0, __spread(args));
newstFetchKey.current = key === undefined ? DEFAULT_KEY : key;
}
var currentFetchKey = newstFetchKey.current; // 这里必须用 fetchsRef而不能用 fetches。
// 否则在 reset 完,立即 run 的时候,这里拿到的 fetches 是旧的。
var currentFetch = fetchesRef.current[currentFetchKey];
if (!currentFetch) {
var newFetch = new Fetch(servicePersist, config, subscribe.bind(null, currentFetchKey), {
data: initialData
});
currentFetch = newFetch.state;
setFetches(function (s) {
// eslint-disable-next-line no-param-reassign
s[currentFetchKey] = currentFetch;
return __assign({}, s);
});
}
return currentFetch.run.apply(currentFetch, __spread(args));
}, [fetchKey, subscribe, ready]);
var runRef = react_1.useRef(run);
runRef.current = run; // cache
useUpdateEffect_1["default"](function () {
if (cacheKey) {
cache_1.setCache(cacheKey, cacheTime, {
fetches: fetches,
newstFetchKey: newstFetchKey.current
});
}
}, [cacheKey, fetches]); // for ready
var hasTriggeredByReady = react_1.useRef(false);
useUpdateEffect_1["default"](function () {
if (ready) {
if (!hasTriggeredByReady.current && readyMemoryParams.current) {
runRef.current.apply(runRef, __spread(readyMemoryParams.current));
}
hasTriggeredByReady.current = true;
}
}, [ready]); // 第一次默认执行
react_1.useEffect(function () {
var _a;
if (!manual) {
// 如果有缓存,则重新请求
if (Object.keys(fetches).length > 0) {
// 如果 staleTime 是 -1则 cache 永不过期
// 如果 statleTime 超期了,则重新请求
var cacheStartTime = cacheKey && ((_a = cache_1.getCache(cacheKey)) === null || _a === void 0 ? void 0 : _a.startTime) || 0;
if (!(staleTime === -1 || new Date().getTime() - cacheStartTime <= staleTime)) {
/* 重新执行所有的 cache */
Object.values(fetches).forEach(function (f) {
f.refresh();
});
}
} else {
// 第一次默认执行,可以通过 defaultParams 设置参数
runRef.current.apply(runRef, __spread(defaultParams));
}
}
}, []); // 重置 fetches
var reset = react_1.useCallback(function () {
Object.values(fetchesRef.current).forEach(function (f) {
f.unmount();
});
newstFetchKey.current = DEFAULT_KEY;
setFetches({}); // 不写会有问题。如果不写,此时立即 run会是老的数据
fetchesRef.current = {};
}, [setFetches]); // refreshDeps 变化,重新执行所有请求
useUpdateEffect_1["default"](function () {
if (!manual) {
/* 全部重新执行 */
Object.values(fetchesRef.current).forEach(function (f) {
f.refresh();
});
}
}, __spread(refreshDeps)); // 卸载组件触发
react_1.useEffect(function () {
return function () {
Object.values(fetchesRef.current).forEach(function (f) {
f.unmount();
});
};
}, []);
var notExecutedWarning = react_1.useCallback(function (name) {
return function () {
console.warn("You should't call " + name + " when service not executed once.");
};
}, []);
return __assign(__assign({
loading: ready && !manual || defaultLoading,
data: initialData,
error: undefined,
params: [],
cancel: notExecutedWarning('cancel'),
refresh: notExecutedWarning('refresh'),
mutate: notExecutedWarning('mutate')
}, fetches[newstFetchKey.current] || {}), {
run: run,
fetches: fetches,
reset: reset
});
}
exports["default"] = useAsync;