使用ts在vue3项目中实现一个钩子:useRequest
目标
封装一个处理get请求的钩子,维护单独的数据,loading,(分页)
步骤
……本来打算写细分的,奈何写作功力一般,直接贴完整代码了,水平一般,代码里都有注释,有问题或者改进的地方可以评论区讨论
import { message } from "ant-design-vue";
import { computed, reactive, unref, watch } from "vue"
type TResult = any
type TPagination = Partial<IPagination>
// 配置
interface IOptions {
saveVal: (result: TResult) => void; // 保存请求回的数据结构
handleErr: (err: any) => void; // 请求的错误处理
rightCode: number; // 请求正确的 code 码
errMessage: boolean; // 请求发生错误是否 message 提示
withPagination?: boolean; // get 请求是否携带分页参数
getParams: any; // 请求参数
}
interface IPagination {
pageSize: number;
current: number;
total: number;
hideOnSinglePage: boolean;
}
interface IState {
loading: boolean;
data: Array<any>;
pagination: TPagination;
}
const DEFAULT_VAL = {
pageSize: 10,
current: 1,
saveVal: (result: TResult) => result.data.content || [],
handleErr: (result: TResult) => message.error(result.msg),
rightCode: 200,
withPagination: true
}
/**
* 封装网络请求
* @param requestFun 请求函数
* @param options 配置项
* @returns
*/
export const useRequest = (requestFun: (...args: any[]) => any, options: Partial<IOptions> & TPagination = {}) => {
const state = reactive<IState>({
loading: false,
data: [],
pagination: {
pageSize: options.pageSize || DEFAULT_VAL.pageSize,
current: options.current || DEFAULT_VAL.current,
total: 0,
hideOnSinglePage: ('hideOnSinglePage' in options) ? options.hideOnSinglePage : true
}
})
const withPaginationRequestParams = computed(() => {
return (Object.hasOwn(options, 'withPagination') ? options.withPagination : DEFAULT_VAL.withPagination) ? {
...unref(options.getParams) || {},
pageNum: state.pagination.current,
pageSize: state.pagination.pageSize,
} : {
...unref(options.getParams) || {},
}
})
async function fetchData(...params: any) {
state.loading = true;
try {
// 如果传入 params 的话,使用 params ,否则使用 withPaginationRequestParams 当作请求参数
const result = await (params.length ? requestFun(...params) : requestFun(withPaginationRequestParams.value));
if (result.code === (options.rightCode || DEFAULT_VAL.rightCode)) {
state.pagination.total = result.data?.totalSize || 0;
state.data = options.saveVal ? options.saveVal(result) : DEFAULT_VAL.saveVal(result);
} else {
// 如果需要 message 提示,单独进行 错误msg message提醒
options.errMessage && message.error(result.msg)
return Promise.reject();
}
} catch (err) {
if (options.handleErr) {
options.handleErr(err);
} else {
DEFAULT_VAL.handleErr(err)
}
} finally {
state.loading = false;
}
}
// 重置分页信息
function resetPagination() {
state.pagination.pageSize = DEFAULT_VAL.pageSize;
state.pagination.current = DEFAULT_VAL.current;
}
async function handleTableChange(pagination: TPagination) {
state.pagination.pageSize = pagination.pageSize;
state.pagination.current = pagination.current;
}
watch(() => [state.pagination.pageSize, state.pagination.current], () => {
fetchData()
})
return {
state,
withPaginationRequestParams,
// func
fetchData,
resetPagination,
handleTableChange,
}
}