@orca-fe/hooks
Version:
React Hooks Collections
227 lines (223 loc) • 8.18 kB
JavaScript
import _regeneratorRuntime from "@babel/runtime/helpers/esm/regeneratorRuntime";
import _asyncToGenerator from "@babel/runtime/helpers/esm/asyncToGenerator";
import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
/* eslint-disable @typescript-eslint/no-explicit-any */
import { useDocumentVisibility, useMemoizedFn } from 'ahooks';
import React, { useContext, useEffect, useRef, useState } from 'react';
import useInterval from "./useInterval";
export var isFetchResult = value => {
if (value != null && typeof value === 'object') {
if ('data' in value) {
return true;
}
}
return false;
};
export var UseServiceContext = /*#__PURE__*/React.createContext({});
var cache = {};
export function defaultFormatter(res) {
if (isFetchResult(res)) {
return res.data;
}
return res;
}
export function useService(_service, options = {}) {
var _stateMgr$state, _stateMgr$setState;
var globalOptions = useContext(UseServiceContext);
var _globalOptions$option = _objectSpread(_objectSpread({}, globalOptions), options),
_globalOptions$option2 = _globalOptions$option.defaultParams,
defaultParams = _globalOptions$option2 === void 0 ? [] : _globalOptions$option2,
initialData = _globalOptions$option.initialData,
_globalOptions$option3 = _globalOptions$option.manual,
manual = _globalOptions$option3 === void 0 ? false : _globalOptions$option3,
onError = _globalOptions$option.onError,
onSuccess = _globalOptions$option.onSuccess,
cacheKey = _globalOptions$option.cacheKey,
_globalOptions$option4 = _globalOptions$option.keepSuccessData,
keepSuccessData = _globalOptions$option4 === void 0 ? true : _globalOptions$option4,
_globalOptions$option5 = _globalOptions$option.formatter,
formatter = _globalOptions$option5 === void 0 ? defaultFormatter : _globalOptions$option5,
_globalOptions$option6 = _globalOptions$option.pollingInterval,
pollingInterval = _globalOptions$option6 === void 0 ? 0 : _globalOptions$option6,
_globalOptions$option7 = _globalOptions$option.pollingWhenHidden,
pollingWhenHidden = _globalOptions$option7 === void 0 ? false : _globalOptions$option7,
stateMgr = _globalOptions$option.stateMgr,
onFinish = _globalOptions$option.onFinish,
_globalOptions$option8 = _globalOptions$option.throwOnError,
throwOnError = _globalOptions$option8 === void 0 ? true : _globalOptions$option8;
var service = useMemoizedFn(_service);
// 组件状态控制 start
var _useState = useState(() => {
var _cache;
return {
loading: false,
data: (_cache = cache[cacheKey !== null && cacheKey !== void 0 ? cacheKey : '']) !== null && _cache !== void 0 ? _cache : initialData,
params: defaultParams
};
}),
_useState2 = _slicedToArray(_useState, 2),
__state = _useState2[0],
__setState = _useState2[1];
var state = (_stateMgr$state = stateMgr === null || stateMgr === void 0 ? void 0 : stateMgr.state) !== null && _stateMgr$state !== void 0 ? _stateMgr$state : __state;
var _setState = (_stateMgr$setState = stateMgr === null || stateMgr === void 0 ? void 0 : stateMgr.setState) !== null && _stateMgr$setState !== void 0 ? _stateMgr$setState : __setState;
var _this = useRef({
unloaded: false,
ticket: 0,
loading: false
}).current;
var setState = useMemoizedFn((newState = {}) => {
if (!_this.unloaded) {
if (cacheKey != null && newState.data) {
cache[cacheKey] = newState.data;
}
_setState(state => _objectSpread(_objectSpread({}, state), newState));
// _setState({ ...state, ...newState });
}
});
// 组件状态控制 end
var _state$loading = state.loading,
loading = _state$loading === void 0 ? false : _state$loading,
data = state.data,
error = state.error,
params = state.params;
var refresh = () => Promise.resolve();
var visible = useDocumentVisibility();
// 轮询
var timer = useInterval(() => {
if (visible || !pollingWhenHidden) {
refresh();
}
}, pollingInterval || undefined);
// 发起请求
var load = useMemoizedFn( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(...args) {
var ticket, _res, formattedData;
return _regeneratorRuntime().wrap(function _callee$(_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
ticket = performance.now();
_this.ticket = ticket;
_this.loading = true;
setState({
loading: true,
error: undefined
});
timer.reset();
_context.prev = 5;
_context.next = 8;
return service(...args);
case 8:
_res = _context.sent;
formattedData = formatter(_res);
if (!(throwOnError && formattedData instanceof Error)) {
_context.next = 12;
break;
}
throw formattedData;
case 12:
if (keepSuccessData && formattedData == null) {
formattedData = data;
}
if (_this.ticket === ticket) {
// 请求结果有效
_this.loading = false;
setState({
params: args,
loading: false,
data: formattedData
});
if (formattedData != null) {
if (typeof onSuccess === 'function') {
onSuccess(formattedData, args);
}
} else if (typeof onError === 'function') {
// 暂时禁用 onError 的触发逻辑,数据问题不做 Error 处理
// onError(new Error('result is undefined'), args);
}
if (typeof onFinish === 'function') {
onFinish(_res, args);
}
} else {
console.warn('Request response out date.');
}
return _context.abrupt("return", formattedData);
case 17:
_context.prev = 17;
_context.t0 = _context["catch"](5);
console.error(_context.t0);
if (_this.ticket === ticket) {
_this.loading = false;
if (keepSuccessData) {
setState({
error: _context.t0,
loading: false
});
} else {
setState({
error: _context.t0,
loading: false,
data: undefined
});
}
if (typeof onError === 'function') {
onError(_context.t0, args);
}
}
case 21:
return _context.abrupt("return", undefined);
case 22:
case "end":
return _context.stop();
}
}, _callee, null, [[5, 17]]);
})));
refresh = useMemoizedFn( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee2() {
return _regeneratorRuntime().wrap(function _callee2$(_context2) {
while (1) switch (_context2.prev = _context2.next) {
case 0:
if (!params) {
_context2.next = 2;
break;
}
return _context2.abrupt("return", load(...params));
case 2:
return _context2.abrupt("return", undefined);
case 3:
case "end":
return _context2.stop();
}
}, _callee2);
})));
var mutate = useMemoizedFn(data => {
if (_this.unloaded) return;
_setState(oldState => _objectSpread(_objectSpread({}, oldState), {}, {
// @ts-expect-error
data: typeof data === 'function' ? data(oldState.data) : data
}));
});
var cancel = useMemoizedFn(() => {
_this.ticket = Date.now();
});
useEffect(() => {
_this.loading = false;
_this.unloaded = false;
// 如果 manual === false,则需要主动加载一次
if (!manual) {
load(...defaultParams);
}
return () => {
_this.unloaded = true;
};
}, []);
return {
loading,
params,
data,
error,
mutate,
run: load,
refresh,
cancel
};
}
export default useService;