背景
在PC的开发项目中,一定会有一些列表查询的页面,无外乎,就是查询条件和table中回显的数据的不同,然后再加上一个分页功能,为了提高效率,于是准备将整个查询与更改页码的封装在一个组件当中,使用时只需将组件引入,传入所需要的参数就可以使用,数据请求部分用一个自定义的hook来解决,这部分是借鉴了别人的写法链接,觉得很好,就放到自己代码中,也进行了一些改动。hook的基本使用就不再赘述,如果还不了解的,可以去React 官网。那么剩下的,需要的准备工作就是:
- 封装一个自定义的useService的hook,来负责数据请求的部分
- 封装table组件
封装自定义 useService
该部分主要负责数据查询,然后将 { loading, response } 暴露出来。每次借用hook特性,依赖 params 的改变,从而重新请求数据。
import { useEffect, useRef, useState } from 'react';
import { isEqual } from 'lodash';
interface res {
result: number;
message: string;
totalcounts: number;
totalpage: number;
[key : string ]: any;
}
const useService = (service: (param: object) => Promise<void>, params: any) => {
const prevParams = useRef(null);
const [loading, setloading] = useState(false);
const [response, setResponse] = useState<res>();
useEffect(() => {
if(!isEqual(prevParams.current, params)) {
prevParams.current = params;
setloading(true);
service(params)
.then(( res: any )=>{
setResponse(res);
setloading(false);
})
.catch( (error: any) => {
setloading(false);
console.log('error', error);
})
}
}, [service, params])
return { loading, response }
}
export default useService;
封装 table 组件
这个部分将整个 table 和 pagination 组件封装起来,只接受请求地址和参数,切换页码的操作放在组件内部,父组件使用的时候,不必在考虑页码的操作,如果你要问为什么单独使用pagination,我只想说个人习惯而已,也可以table自带的,loading的加载组件也是使用的Ant自带的,这些如果你有兴趣,也可以自己写。 children 的话,是放搜索框或者下拉选择框,只是设置查询条件,没有的话可以不加。
useService 使用的时候,就像自定义hook的使用方法一样使用就可以。如果 params 改变,就会触发Ajax请求,获取最新的数据。 updateInPropsParams 这个函数作用主要是用于查询条件更改时,传入 ComponentTable 时的 queryparams 更改时触发,虽然依赖只写 queryparams ,编辑器会报警告,但切忌只写这个,因为只是需要 queryparams 改变才去触发,如果加上 params 会无限请求,直至浏览器卡死。
import useService from '@/hooks/useService.ts';
import { IProps, IPagination, IQueryparamsItem } from './types';
const ComponentTable:FC<IProps> = ({columns,queryparams,queryurl,rowKey,...other}:IProps) => {
const [pagination, setPagination] = useState<IPagination>({
pageNo: 1,
pageSize: 10
})
const [params, setParams] = useState<IQueryparamsItem>({
...pagination,
...queryparams,
})
const updateInPropsParams = useCallback(
() => {
setParams({
...params,
...queryparams
});
setPagination({
...pagination,
pageNo: queryparams.pageNo!,
})
},
[queryparams],
)
useEffect(() => {
updateInPropsParams();
}, [updateInPropsParams]);
const { loading, response } = useService(queryurl, params);
const handlePageChange = (pageNo:number, pageSize?:number) => {
setPagination({
pageNo,
pageSize: pageSize!
})
setParams({
...queryparams
})
}
return (
<div className="com-table">
{
other?.children
}
<Spin spinning={loading}>
<Table
className="list-container"
scroll={{ y: document.body.offsetHeight - 280 }}
rowKey={rowKey}
columns={columns()}
dataSource={response?.list}
pagination={false}
/>
<Pagination
defaultCurrent={pagination.pageNo}
onChange={(pageNo, pageSize) => handlePageChange(pageNo, pageSize)}
hideOnSinglePage
total={response?.pageTotal} />
</Spin>
</div>
)
}
export default ComponentTable
再另附上 ComponentTable 组件的类型声明,大家可以去根据自己的项目更改。
import { ReactElement } from "react";
import { ColumnProps } from "antd/lib/table/interface";
export interface IPagination {
pageNo?: number;
pageSize?: number;
}
export interface IQueryparamsItem extends IPagination{
keyword: string;
}
export interface IProps {
children?: ReactElement;
columns: () => Array<ColumnProps<any>>;
queryparams: IQueryparamsItem;
queryurl: (params:object)=>Promise<void>;
rowKey: (record: any, index: number) => string
}
父组件
如果要在父组件中使用的话,直接引入,就像刚开始说的一样,传入columns,queryurl, queryparams 所需要的参数即可
import ComTable from './ComTable';
import {CloumnsProps} from './types';
import { queryurl } from '@/server/api';
import { IQueryparamsItem } from './ComTable/types.ts';
const { Search } = Input;
const ParentCom:React.FC = () => {
const [params, setParams] = useState<IQueryparamsItem>({
keyword: '',
})
const columns: CloumnsProps = useCallback(
() => {
return [
{
title: '列1',
dataIndex: 'one',
},
{
title: '列2',
dataIndex: 'two',
},
{
title: '列3',
render: (item:any) => {
return (
<>
<Icon
className="columnsIcon"
type="edit"
/>
</>
)
}
},
]
},
[]
)
const handleSearch = (val:string) => {
setParams({
keyword: val,
pageNo: 1,
})
}
return (
<ComTable
columns={()=> columns()}
rowKey={(d: any) => (d.id).toString()}
queryparams={params}
queryurl={getAccountList}
>
<Search style={{ width: 280 }} placeholder="手机号/用户名/昵称" onSearch={(val) => handleSearch(val)} enterButton />
</ComTable>
)
}
export default ParentCom
结尾
虽然功能很小,也希望可给大家一咻咻帮助。我旨在记录下自己的开发过程,顺便做个标记,方便自己以后想看的话,直接翻找。如果有问题,可以帮我指出来,或者有更好的想法,也提出来,我都会改进的~~~感谢!