一、why?
有时候我们需要 Select 组件中数据比较大,可能需要分页的问题,由于 antd 中并没有直接提供 Select 分页功能,我们需要自己写。可能也有很多其他的方案,就是滚动到底部加载,其实这种还是没有分页来的直接,分页的效果与表格相似。
二、需要的组件
- Select 组件
- Pagination 组件
这里的 Select 有两种用法,一种是 option 的数组像的形式,一种是 Option 渲染组件的形式。
三、组件设计
- Option 使用组件的 memo 进行缓存,避免重复渲染。
- type 设计为两个主要组件服务,和外部的数据获取,当然也可以内部实现 ajax 请求在组件内部实现数据获取。
- 使用 dropdownRender 渲染 Select 和 Pagination 两个部分。
四、手动实现
ts
import { Select, Pagination } from "antd";
import { memo, useMemo, useState } from "react";
function OptionComImpl({ data }: any) {
return (
<div>
{data.map((item: any, index: number) => {
return <Select.Option value={item.value} key={index}>{item.label}</Select.Option>;
})}
</div>
);
}
const OptionCom = memo(OptionComImpl);
type ISelectPaginationProps = {
data: any[]
currentPage: number
selectStyles: React.CSSProperties
paginationStyles: React.CSSProperties
paginationProps: any
selectPagniationProps: any
}
const _data = [
{ label: "选项 1", value: "1" },
{ label: "选项 2", value: "2" },
{ label: "选项 3", value: "3" },
{ label: "选项 4", value: "4" },
{ label: "选项 5", value: "5" },
{ label: "选项 6", value: "6" },
{ label: "选项 7", value: "7" },
{ label: "选项 8", value: "8" },
{ label: "选项 9", value: "9" },
{ label: "选项 10", value: "10" },
{ label: "选项 11", value: "11" },
{ label: "选项 12", value: "12" },
{ label: "选项 13", value: "13" },
{ label: "选项 14", value: "14" },
{ label: "选项 15", value: "15" },
{ label: "选项 16", value: "16" },
{ label: "选项 17", value: "17" },
{ label: "选项 18", value: "18" },
{ label: "选项 19", value: "19" },
{ label: "选项 20", value: "20" },
{ label: "选项 21", value: "21" },
{ label: "选项 22", value: "22" },
];
export default function SelectPagination({ data = _data, ...props }: ISelectPaginationProps) {
const [currentPage, setCurrentPage] = useState( props.currentPage || 1); // 当前页码
const [skip] = useState(10);
const dataSource = useMemo(() => {
return data.slice(
skip * (currentPage - 1),
data.length - currentPage * skip > 0 ? currentPage * skip : data.length
);
}, [currentPage, data, skip]);
return (
<div>
<Select
style={{
width: 200,
...props.selectStyles,
}}
dropdownRender={(menu, ...args) => {
return (
<div>
{menu}
<div style={{ padding: '10px 0px'}}>
<Pagination
total={data.length}
showSizeChanger
size="small"
pageSize={skip}
onChange={(page) => {
setCurrentPage(page);
}}
{...props.paginationProps}
/>
</div>
</div>
);
}}
{...props.selectPagniationProps}
>
{dataSource.map((item) => {
return <OptionCom key={item.value} data={data} />;
})}
</Select>
</div>
);
}
五、分析
核心要知晓的点就是 dropdownRender
属性,渲染额外的内容。其中 menu
属性是不好修改的。同时我们需要计算初始分页数据 dataSource
当然也可以根据自己的需求重新实现,所以使用组件式的分页渲染数据。使用 useMemo 计算并缓存计算结果。本示例只是一个简单的示例。
六、示例
七、小结
Select 与 Pagination 组件是一个常用的功能,因为可能 Select 中需要存放的数据比较大,使用滚动的方式也有需要滚动很久,使用分页的方式更加的合理。本文主要讨论的其中一个通用的实现方式,希望能够帮助到大家。