bsl
Version:
基于React的框架和UI组件
106 lines (97 loc) • 3.78 kB
text/typescript
import axios, { AxiosRequestConfig, Canceler, Method } from 'axios';
import * as React from 'react';
import RequestView from '../components/RequestView';
import BSL from '../typings';
type Omit_url = Omit<AxiosRequestConfig, 'url'>;
type Omit_url_method = Omit<Omit_url, 'method'>;
export interface Option extends Omit_url_method {
/** 请求接口的名称 */
api: string;
/**
* app: 整个应用生命周期内缓存
* page: 页面生命周期内缓存
*/
cache?: 'app' | 'page';
/**
* @default 'GET'
*/
method?: Method;
}
export const cacheData: Map<string, any> = new Map();
function useRequest(): [(option: Option) => Promise<BSL.RequestResponse<any>>, React.MutableRefObject<Canceler | null>, (key: string) => void] {
const clearCache = (key: string) => cacheData.delete(key);
const cancelToken = React.useRef<(() => void) | null>(null);
const request = (option: Option): Promise<BSL.RequestResponse<any>> => {
return new Promise((resolve, reject) => {
const { api } = option;
const urlSearchParams = new URLSearchParams();
const createKey = () => JSON.stringify({ api: option.api, params: option.params, data: option.data });
const method = ((option.method || (axios.defaults.method)) || 'get').toLocaleUpperCase() as Method;
const defualtData = RequestView.defaultData;
const contentType = option.headers && option.headers['content-type'] || axios.defaults.headers['content-type'];
const postData: Record<string, string | number | boolean | object> = {};
const isFormData = option.data && option.data instanceof FormData;
const isDataArray = Array.isArray(option.data);
// 判断是否有缓存
if (option.cache) {
const key = createKey();
if (cacheData.has(key)) {
resolve(cacheData.get(key));
return;
}
}
if (defualtData && method === 'POST' && !isFormData && isDataArray === false) {
Object.keys((defualtData)).forEach((key) => {
urlSearchParams.append(key, defualtData[key]);
postData[key] = defualtData[key];
});
}
// 去除object中值为undefined的字段
if (option.data && !isFormData && isDataArray === false) {
Object.keys((option.data)).forEach((key) => {
if (option.data[key] !== undefined) {
if (Array.isArray(option.data[key])) {
urlSearchParams.append(key, JSON.stringify(option.data[key]));
} else {
urlSearchParams.append(key, option.data[key]);
}
postData[key] = option.data[key];
}
});
}
axios({
...option,
data: isFormData || isDataArray ? option.data : (contentType === 'application/json' ? postData : urlSearchParams),
url: api,
method,
cancelToken: new axios.CancelToken((cancel) => {
cancelToken.current = () => cancel('cancel');
})
}).then((res) => {
if (res.status === 200) {
let key: string | undefined ;
// 判断接口是否需要缓存,并将结果储存起来
if (option.cache) {
key = createKey();
cacheData.set(key, res.data);
}
resolve({
...res.data,
key
});
} else {
const response: BSL.RequestResponse<null> = {
data: null,
code: 500,
msg: '网络错误'
};
resolve(response);
}
}).catch((err) => {
reject(err);
});
});
};
return [request, cancelToken, clearCache];
}
export default useRequest;