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'; // 模擬請(qǐng)求數(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: '平臺(tái)名稱', // 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ù)添加屬性,其他屬性將會(huì)應(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 = () => { // 請(qǐng)求數(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í)將會(huì)觸發(fā) useEffect(() => { getList(); }, [pageRefresh, filterRefresh]); const columns = [ { title: '序號(hào)', width: 50, align: 'center', render: (v, r, index) => index + 1 + (pagination.page - 1) * pagination.pageSize, }, { title: '平臺(tái)名稱', width: 180, dataIndex: 'req_psname', }, { title: '請(qǐng)求時(shí)間', width: 140, dataIndex: 'inform_time', }, { title: '通知對(duì)象', 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 = () => { // 請(qǐng)求.. 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="你確定要?jiǎng)h除嗎?" 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: "", }); }; //對(duì)話框信息 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封裝表格常用功能的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
React報(bào)錯(cuò)Too many re-renders解決
這篇文章主要為大家介紹了React報(bào)錯(cuò)Too many re-renders解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12React超詳細(xì)分析useState與useReducer源碼
我正在處理的組件是表單的時(shí)間輸入。表單相對(duì)復(fù)雜,并且是動(dòng)態(tài)生成的,根據(jù)嵌套在其他數(shù)據(jù)中的數(shù)據(jù)顯示不同的字段。我正在用useReducer管理表單的狀態(tài),到目前為止效果很好2022-11-11react實(shí)現(xiàn)導(dǎo)航欄二級(jí)聯(lián)動(dòng)
這篇文章主要為大家詳細(xì)介紹了react實(shí)現(xiàn)導(dǎo)航欄二級(jí)聯(lián)動(dòng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03react中代碼塊輸出,代碼高亮顯示,帶行號(hào),能復(fù)制的問題
這篇文章主要介紹了react中代碼塊輸出,代碼高亮顯示,帶行號(hào),能復(fù)制的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-09-09React中Portals與錯(cuò)誤邊界處理實(shí)現(xiàn)
本文主要介紹了React中Portals與錯(cuò)誤邊界處理實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-07-07