174 lines
4.1 KiB
TypeScript
174 lines
4.1 KiB
TypeScript
import { createAxiosToken } from '@/hooks/use-chunk-request';
|
|
import { useRequest } from 'ahooks';
|
|
import { message } from 'antd';
|
|
import { CancelTokenSource } from 'axios';
|
|
import { useEffect, useRef, useState } from 'react';
|
|
|
|
/**
|
|
|
|
* generic hook to query data list
|
|
* @template ListItem
|
|
* @param Params - query params type, e.g. { page: number; perPage: number }
|
|
* @param option.fetchList: (params, extra) => Promise<{ items: ListItem[] }>
|
|
* @returns loading, dataList, fetchData, cancelRequest
|
|
*/
|
|
export function useQueryDataList<
|
|
ListItem,
|
|
Params = any,
|
|
Response = Array<ListItem>
|
|
>(option: {
|
|
key: string;
|
|
responseType?: 'array' | 'object';
|
|
fetchList: (
|
|
params: Params,
|
|
options?: any
|
|
) => Promise<Global.PageResponse<ListItem>>;
|
|
getLabel?: (item: ListItem) => string;
|
|
getValue?: (item: ListItem) => any;
|
|
errorMsg?: string;
|
|
debounceWait?: number;
|
|
}): {
|
|
loading: boolean;
|
|
dataList: Array<ListItem & { label: string; value: any }>;
|
|
cancelRequest: () => void;
|
|
fetchData: (params: Params, extra?: any) => Promise<Response>;
|
|
} {
|
|
const {
|
|
key,
|
|
fetchList,
|
|
getLabel,
|
|
getValue,
|
|
responseType = 'array',
|
|
errorMsg
|
|
} = option;
|
|
const axiosTokenRef = useRef<CancelTokenSource | null>(null);
|
|
const [dataList, setDataList] = useState<
|
|
Array<ListItem & { label: string; value: any }>
|
|
>([]);
|
|
|
|
const {
|
|
runAsync: fetchData,
|
|
loading,
|
|
cancel
|
|
} = useRequest(
|
|
async (params: Params, extra?: any) => {
|
|
axiosTokenRef.current?.cancel();
|
|
axiosTokenRef.current = createAxiosToken();
|
|
const res = await fetchList(params, {
|
|
token: axiosTokenRef.current?.token,
|
|
...(extra || {})
|
|
});
|
|
|
|
setDataList(
|
|
res.items?.map((item: ListItem) => ({
|
|
...item,
|
|
label: getLabel ? getLabel(item) : (item as any).name,
|
|
value: getValue ? getValue(item) : (item as any).id
|
|
})) || []
|
|
);
|
|
|
|
return responseType === 'array' ? res.items || [] : res;
|
|
},
|
|
{
|
|
manual: true,
|
|
debounceWait: option.debounceWait || 300,
|
|
onSuccess: () => {},
|
|
onError: (error) => {
|
|
message.error(
|
|
error?.message || errorMsg || `Failed to fetch ${key} list`
|
|
);
|
|
setDataList([]);
|
|
}
|
|
}
|
|
);
|
|
|
|
const cancelRequest = () => {
|
|
cancel();
|
|
axiosTokenRef.current?.cancel();
|
|
};
|
|
|
|
useEffect(() => {
|
|
return () => {
|
|
cancel();
|
|
axiosTokenRef.current?.cancel();
|
|
};
|
|
}, []);
|
|
|
|
return {
|
|
loading,
|
|
dataList,
|
|
cancelRequest,
|
|
fetchData
|
|
};
|
|
}
|
|
|
|
export function useQueryData<Detail, Params = any>(option: {
|
|
key: string;
|
|
delay?: number;
|
|
fetchDetail: (params: Params, options?: any) => Promise<Detail>;
|
|
getData?: (response: Detail, params?: any) => any;
|
|
errorMsg?: string;
|
|
}): {
|
|
loading: boolean;
|
|
detailData: Detail;
|
|
cancelRequest: () => void;
|
|
fetchData: (params: Params, extra?: any) => Promise<Detail>;
|
|
} {
|
|
const { key, fetchDetail, getData, errorMsg, delay } = option;
|
|
const axiosTokenRef = useRef<CancelTokenSource | null>(null);
|
|
const [detailData, setDetailData] = useState<Detail>({} as Detail);
|
|
|
|
const {
|
|
runAsync: fetchData,
|
|
loading,
|
|
cancel
|
|
} = useRequest(
|
|
async (params: Params, extra?: any) => {
|
|
axiosTokenRef.current?.cancel();
|
|
axiosTokenRef.current = createAxiosToken();
|
|
const res = await fetchDetail(params, {
|
|
token: axiosTokenRef.current?.token,
|
|
...(extra || {})
|
|
});
|
|
|
|
if (delay) {
|
|
await new Promise((resolve) => {
|
|
setTimeout(resolve, delay);
|
|
});
|
|
}
|
|
|
|
setDetailData(getData ? getData(res, params) : res);
|
|
|
|
return res;
|
|
},
|
|
{
|
|
manual: true,
|
|
onSuccess: () => {},
|
|
onError: (error) => {
|
|
message.error(
|
|
error?.message || errorMsg || `Failed to fetch ${key} data`
|
|
);
|
|
setDetailData({} as Detail);
|
|
}
|
|
}
|
|
);
|
|
|
|
const cancelRequest = () => {
|
|
cancel();
|
|
axiosTokenRef.current?.cancel();
|
|
};
|
|
|
|
useEffect(() => {
|
|
return () => {
|
|
cancelRequest();
|
|
};
|
|
}, []);
|
|
|
|
return {
|
|
loading,
|
|
detailData,
|
|
cancelRequest,
|
|
fetchData
|
|
};
|
|
}
|