React通過hook實(shí)現(xiàn)封裝表格常用功能
封裝內(nèi)容
- 配置分頁:usePagination
- 生成過濾項(xiàng):useFilter
- 獲取表格選擇配置:useSelect
- 生成批量刪除按鈕:useDelete
- 生成模態(tài)框:useModal
基于react@18.2.0,antd@5.12.5
示例
render部分:
<React.Fragment>
<Form layout="inline">
{DeleteEle}
{FilterEles}
</Form>
<Table
{...{
columns,
dataSource: list || [],
rowSelection,
pagination: paginationConfig,
rowKey: 'inform_uuid',
}}
/>
{ModalEle}
</React.Fragment>
效果:

完整代碼
import React, { useState, useEffect } from 'react';
import { Form, Table, Tag } from 'antd';
import Detail from './Detail'; // 詳情彈框的內(nèi)容
import { LIST_RES } from '../store'; // 模擬請求數(shù)據(jù)
import TableGenerator from '../TableGenerator'; // 封裝的鉤子
const { useFilter, usePagination, useSelect, useDelete, useModal } =
TableGenerator;
const TestTable = () => {
// 1. 生成過濾項(xiàng)。
// 傳入配置,可以自行擴(kuò)展。目前支持輸入框、日期范圍選擇器、普通選擇器
// FilterEles:過濾項(xiàng)表單項(xiàng)
// filterRefresh:暴露出來告訴外層需要重新獲取數(shù)據(jù)了
const { FilterEles, filter, filterRefresh } = useFilter([
{
name: 'name', // 字段
label: '平臺名稱', // placeholder
type: 'inputString', // 組件類型:字符串輸入框
},
{
name: 'status',
label: '狀態(tài)',
type: 'select', // 組件類型:選擇器
initValue: 0, // 默認(rèn)數(shù)據(jù)(可選)
options: [
{ value: 0, label: '全部狀態(tài)' },
{ value: 1, label: '成功' },
{ value: 2, label: '失敗' },
],
},
{
name: ['start_date', 'end_date'],
label: ['開始日期', '結(jié)束日期'],
type: 'dateRange', // 組件類型:日期選擇器
},
]);
// 2. 獲取分頁配置。
// pagination:{page,pageSize,total}
// pageRefresh:暴露出來告訴外層需要重新獲取數(shù)據(jù)了
// paginationConfig:作為表格的分頁屬性
const { pagination, setPagination, pageRefresh, paginationConfig } =
usePagination();
// 3. 表格選中配置
// selectedKeys: Array<string>
// rowSelection: 作為表格的選擇屬性
const { selectedKeys, setSelectedKeys, rowSelection } = useSelect();
// 4. 配置模態(tài)框。
// 傳入數(shù)組,用于配置所有彈框類型(詳情、添加、編輯等),目前只支持詳情,可自行擴(kuò)展
// ModalEle: 模態(tài)框組件
// modal: {isShow:boolean, action:string, record:any}
const { ModalEle, modal, setModal } = useModal([
{
title: '詳情', // 彈框標(biāo)題
action: 'detail', // 彈框類型
getComponent: (record) => <Detail data={record} />, // 彈框數(shù)據(jù)
// ... 可以繼續(xù)添加屬性,其他屬性將會應(yīng)用到Modal中 比如footer、handleOk
},
]);
// 5. 批量刪除按鈕,需要搭配useSelect使用
const [DeleteEle] = useDelete({
url: 'ajax/deleteItem.json',
data: {
uuids: selectedKeys,
},
success: () => { // 可選,刪除成功后還需要調(diào)用的內(nèi)容
setSelectedKeys([]);
getList();
},
keys: selectedKeys, // 用于判斷按鈕是否可點(diǎn)擊
});
const [list, setList] = useState([]);
const getList = () => {
// 請求數(shù)據(jù), 可傳入filter和pagination作為參數(shù)
Ajax.ajax({
url: 'GetSmsInformList',
data: {
page: pagination.page,
pageSize: pagination.pageSize,
filter
},
success: (data) => {
setList(data.list);
setPagination({
...pagination,
page: data.page,
total: data.total
});
}
});
// 模擬數(shù)據(jù)
// const data = LIST_RES.data;
// setList(data.list);
// setPagination({
// ...pagination,
// page: data.page,
// total: data.total,
// });
};
// 觸發(fā)刷新:修改page、pageSize、點(diǎn)擊查詢、重置時(shí)將會觸發(fā)
useEffect(() => {
getList();
}, [pageRefresh, filterRefresh]);
const columns = [
{
title: '序號',
width: 50,
align: 'center',
render: (v, r, index) =>
index + 1 + (pagination.page - 1) * pagination.pageSize,
},
{
title: '平臺名稱',
width: 180,
dataIndex: 'req_psname',
},
{
title: '請求時(shí)間',
width: 140,
dataIndex: 'inform_time',
},
{
title: '通知對象',
width: 180,
dataIndex: 'inform_pnumbers',
render: (v) => v.join(', '),
},
{
title: '通知內(nèi)容',
width: 200,
dataIndex: 'inform_content',
},
{
title: '通知結(jié)果',
width: 80,
dataIndex: 'inform_result',
render: (v) =>
v === 0 ? (
<Tag color="#87d068">成功</Tag>
) : (
<Tag color="#f50">失敗</Tag>
),
},
{
title: '操作',
width: 60,
render: (v, record) => (
<React.Fragment>
<a
onClick={() => {
setModal({
action: 'detail',
isShow: true,
record,
});
}}
>
詳情
</a>
</React.Fragment>
),
},
];
return (
<React.Fragment>
<Form layout="inline">
{DeleteEle}
{FilterEles}
</Form>
<Table
{...{
scroll: { x: 1170, y: '70vh' },
columns,
dataSource: list || [],
rowSelection,
pagination: paginationConfig,
rowKey: 'inform_uuid',
}}
/>
{ModalEle}
</React.Fragment>
);
};
export default TestTable;
Hook封裝
usePagination
配置表格的分頁功能
const usePagination = () => {
// 默認(rèn)數(shù)據(jù)
const [pagination, setPagination] = useState({
page: 1,
pageSize: 10,
total: 0,
});
// 用于觸發(fā)外層的刷新
const [pageRefresh, setPageRefresh] = useState(false);
const config = {
size: "small",
showQuickJumper: false,
total: pagination.total,
current: pagination.page,
showSizeChanger: true,
onChange: (current) => {
setPagination({
...pagination,
page: current,
});
setPageRefresh(() => !pageRefresh); // 修改頁數(shù)后,通知外層刷新
},
pageSize: pagination.pageSize,
onShowSizeChange: (page, pageSize) => {
setPagination({
page,
pageSize,
});
setPageRefresh(() => !pageRefresh);// 修改頁碼后,通知外層刷新
},
};
return {
pagination,
pageRefresh,
setPagination,
paginationConfig: config,
};
};
useSelect
配置表格的選擇功能
const useSelect = () => {
const [selectedKeys, setSelectedKeys] = useState([]);
const rowSelection = {
onChange: (selectedKeys) => {
setSelectedKeys(selectedKeys);
},
selectedRowKeys: selectedKeys,
};
return { selectedKeys, rowSelection, setSelectedKeys };
};
useDelete
配置表格的批量刪除按鈕
const useDelete = ({ url = "", data = {}, success = null, keys = [] }) => {
const handleDel = () => {
// 請求..
message.success("刪除成功");
success && success(); //
};
const DeleteEle = (
<React.Fragment>
{ /**OPER.isDelete : 當(dāng)有權(quán)限時(shí)才顯示 */}
{OPER.isDelete && (
<Form.Item>
{keys.length === 0 ? (
<Button icon={<DeleteOutlined />} size="small" disabled>
批量刪除
</Button>
) : (
<Popconfirm
title="批量刪除"
description="你確定要刪除嗎?"
okText="確定"
cancelText="取消"
onConfirm={handleDel}
>
<Button
type="primary"
danger
icon={<DeleteOutlined />}
size="small"
>
批量刪除
</Button>
</Popconfirm>
)}
</Form.Item>
)}
</React.Fragment>
);
return [DeleteEle];
};
useFilter
配置過濾項(xiàng),附帶查詢、重置按鈕
import { initFilter, getFormItem } from "./utils"; // 根據(jù)配置配置初始化filter數(shù)據(jù) ; 根據(jù)配置獲取組件
const useFilter = (config = []) => {
const [filter, setFilter] = useState(initFilter(config));
const [refresh, setRefresh] = useState(false);
// 重置過濾項(xiàng)
const handleResetFilter = () => {
setFilter(initFilter(config));
setRefresh(!refresh); // 通知外層刷新
};
// 觸發(fā)查詢
const handleSearch = () => {
setRefresh(!refresh); // 通知外層刷新
};
// 修改日期類型
const handleDateChange = ([startField, endField], [startTime, endTime]) => {
setFilter({ ...filter, [startField]: startTime, [endField]: endTime });
};
// 修改input 類型
const handleInputChange = (e) => {
const { name, value } = e.target;
setFilter({ ...filter, [name]: value });
};
// 修改select 類型
const handleSelectChange = (name, value) => {
setFilter({ ...filter, [name]: value });
};
// 根據(jù)配置生成表單項(xiàng)
const FormItemEles = getFormItem(config, {
filter,
handleInputChange,
handleSelectChange,
handleDateChange,
});
const HandlerEles = [
<Form.Item>
<Button
type="primary"
size="small"
onClick={handleSearch}
icon={<SearchOutlined />}
>
查詢
</Button>
</Form.Item>,
<Form.Item>
<Button
type="primary"
size="small"
onClick={handleResetFilter}
icon={<ReloadOutlined />}
>
重置
</Button>
</Form.Item>,
];
return {
filter,
FilterEles: [...FormItemEles, ...HandlerEles],
filterRefresh: refresh,
};
};
initFilter:根據(jù)不同類型初始化filter數(shù)據(jù)
const initFilter = (arr) => {
const obj = {};
arr.forEach((item) => {
switch (item.type) {
case "inputString":
obj[item.name] = item.initValue || "";
break;
case "select":
obj[item.name] = item.initValue || 0;
break;
case "dateRange":
item.name.forEach((name) => {
obj[name] = "";
});
break;
default:
break;
}
});
return obj;
};
getFormItem:根據(jù)不同的類型生成表單項(xiàng)組件
const getFormItem = (
arr,
{ filter, handleInputChange, handleSelectChange, handleDateChange }
) => {
const Eles = [];
arr.forEach((item) => {
const name = item.name;
const label = item.label;
const value = filter[name];
switch (item.type) {
case "inputString":
Eles.push(
<Form.Item>
<Input
size="small"
placeholder={label}
name={name}
value={value}
onChange={handleInputChange}
/>
</Form.Item>
);
break;
case "select":
Eles.push(
<Form.Item>
<Select
size="small"
style={{ width: 120 }}
onChange={(v) => {
handleSelectChange(name, v);
}}
name={name}
value={value}
options={item.options}
/>
</Form.Item>
);
break;
case "dateRange":
Eles.push(
<Form.Item>
<RangePicker
onChange={(dates) => {
handleDateChange(name, dates);
}}
value={[filter[name[0]], filter[name[1]]]}
placeholder={label}
size="small"
/>
</Form.Item>
);
default:
break;
}
});
return Eles;
};
useModal
配置模態(tài)框
const useModal = (
config = [
{
title: "詳情",
action: "detail",
getComponent: (record)=><div>詳情</div>,
},
]
) => {
const [modal, setModal] = useState({
isShow: false,
record: null,
action: "",
});
const handleCancel = () => {
setModal({
isShow: false,
record: null,
action: "",
});
};
//對話框信息
let modalProps = {
open: modal.isShow,
onCancel: handleCancel,
maskClosable: false,
footer: null,
};
const currentModal = config.find((item) => item.action === modal.action); // 找到當(dāng)前模態(tài)框數(shù)據(jù)
if (currentModal) {
const { action, getComponent, ...other } = currentModal;
// 配置傳進(jìn)來的其余屬性
modalProps = {
...modalProps,
...other,
};
}
const ModalEle = (
<Modal width="80%" {...modalProps}>
{currentModal && currentModal.getComponent(modal.record)}
</Modal>
);
return { ModalEle, modal, setModal };
};
源碼
以上就是React通過hook實(shí)現(xiàn)封裝表格常用功能的詳細(xì)內(nèi)容,更多關(guān)于React hook封裝表格常用功能的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
React項(xiàng)目中fetch實(shí)現(xiàn)跨域接收傳遞session的解決方案
這篇文章主要介紹了React項(xiàng)目中fetch實(shí)現(xiàn)跨域接收傳遞session的解決方案,本次項(xiàng)目使用了react框架,同時(shí)使用fetch取代ajax作為獲取接口數(shù)據(jù)的交互方法,下面就對這次問題的解決做個(gè)總結(jié),需要的朋友可以參考下2022-04-04
React使用react-sortable-hoc如何實(shí)現(xiàn)拖拽效果
這篇文章主要介紹了React使用react-sortable-hoc如何實(shí)現(xiàn)拖拽效果問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-07-07
react中關(guān)于Context/Provider/Consumer傳參的使用
這篇文章主要介紹了react中關(guān)于Context/Provider/Consumer傳參的使用,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-09-09

