项目场景
写过小程序或者h5等移动端的都知道,请求后台列表接口都会有分页
分页的好处
- 1.提高接口响应速度(众所周知查10条数据和查10000条数据响应的时间肯定是有区别的)
- 2.提高前端渲染性能,一下子查出所有数据前端不做虚拟列表的情况下会卡
- 3.节省服务器压力
引出的问题
小声比比:你服务器压力小了,我特么代码量增加了,每个页面都需要去定义当前列表的状态(是否有下一页),当前列表是第几页,还需要累增,以及列表的每页请求多少条!我就是一个臭敲代码的啊,我只想早点下班!!特别是一个页面请求好几个列表的写这些重复代码很烦的好不好
那么如何只用一行代码复用这些重复的参数??我们可以用hooks来解决
以前的做法
定义类型
写请求方法,并且设置列表数据及状态
现在的做法
定义类型+请求方法
就是这么简单,直接用就完事儿
hooks的由来
hooks是在react16.8.0新增的特性,碰巧那时我也正在写react,写过react的都知道,那时候主流是类组件,hooks是
什么玩意儿啊??好用么?看看hooks解决了什么问题吧
-
1.在组件之间复用状态逻辑很难
-
2.复杂组件变得难以理解
-
3.难以理解的class(上述提到的类组件)
当时用了一下,觉得这玩意儿确实好使,比类组件写起来方便多了,引入然后用就行了。
Vue3:React你小子这个hooks理念不错,拿来把你
这时候也就有了我们vue3中的各种hooks
自定义hooks
hooks一般命名为useXXXXX,推荐一个vue官方的hooks库,vueUses,里面有各种杂七杂八的hooks,遗憾的就是这个库是英文文档,不过问题不大。丝毫不影响它好用
vueUses官网地址
接口函数示例及响应示例
export interface IListResponse<T> {
code: number
rows: T,
msg: string,
[key: string]: any
}
export type TApiListRequest<T> = Promise<IListResponse<T>>
/**
* 客户列表
* @param params
* @returns
*/
export const reqCustomerlistPage = <T>(params?: T): TApiListRequest<ICustomerListItem[]> => {
return new Promise(async (resolve) => {
const url = `/core/customer/listPage`;
let result = await $http.post(url, params);
resolve(result);
});
};
列表请求自定义hooks的代码
interface IUseRequestListConfig<T> {
/** 当前页自定义请求字段,默认是pageNum */
pageNumFields?: string
/** 每页数量自定义请求字段,默认是pageSize */
pageSizeFields?: string
/** 返回数据中列表的字段,默认是rows */
dataFields?: string
/**封装好的接口api */
apiFunction: (params?: any) => TApiListRequest<T[]>
}
// 加载状态
enum TLoadStatus {
LOAD_MORE = 'loadmore', //# 加载更多
LOADING = 'loading', //#加载中
NOMORE = 'nomore', //#没有更多
}
/**
* 列表请求hooks
* @param originConfig 配置
* @returns
*/
export const useRequestList = <T>(originConfig: IUseRequestListConfig<T>) => {
// 默认配置
const defaultConfig = {
pageNumFields: "pageNum", pageSizeFields: "pageSize", dataFields: "rows" }
// 合并后配置
const config: IUseRequestListConfig<T> = {
...defaultConfig, ...originConfig }
interface IState {
params: {
[x: string]: number;
};
}
const state = reactive<IState>({
params: {
[config.pageNumFields!]: 1,
[config.pageSizeFields!]: 10,
},
})
const dataSource = ref<T[]>([])
const status = ref<TLoadStatus>(TLoadStatus.LOAD_MORE)
/**
* 加载数据
* @param otherParams
* @returns
*/
const loadData = async <T extends Record<string, unknown>>(otherParams?: T) => {
if (status.value === TLoadStatus.NOMORE) return;
status.value = TLoadStatus.LOADING;
let result = await config.apiFunction({
...state.params, ...otherParams });
if (state.params.pageNum === 1) dataSource.value = [];
state.params.pageNum += 1;
dataSource.value = [...dataSource.value, ...result[config.dataFields!]];
status.value = dataSource.value.length < result.total ? TLoadStatus.LOAD_MORE : TLoadStatus.NOMORE;
}
/**
* 刷新列表
* beforeRfresh用于在刷新之前清空某些查询字段
*/
const handleRefresh = async <T extends Record<string, unknown>>(otherParams?: T, beforeRfresh?: () => void) => {
beforeRfresh?.()
status.value = TLoadStatus.LOAD_MORE;
state.params = {
...state.params,
[config.pageNumFields!]: 1,
};
await loadData(otherParams);
};
return {
loadData,
dataSource,
status,
handleRefresh
}
}
使用方法
const {
handleRefresh, loadData, status, dataSource } = useRequestList({
apiFunction: reqCustomerlistPage });
没错,请求一个列表一行代码就搞定(我终于可以愉快的摸鱼了)
使用中分别在需要请求的生命周期和钩子函数中抛出该hooks的方法就行,在这个hooks中,返回的数据和当前列表的状态是响应式的,列表最下面的加载更多组件需要给的当前状态通过修改TLoadStatus这个枚举就行,有些组件库的加载状态可能是0,1,2,有些可能是我这种的。