"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;