react中hook封装一个table组件 与 useColumns组件

目录

  • 1:react中hook封装一个table组件
    • 依赖
    • CommonTable / index.tsx
    • 使用组件
    • 效果
  • 2:useColumns组件
    • useColumns.tsx
    • 使用

1:react中hook封装一个table组件

依赖

cnpm i react-resizable --save
cnpm i ahooks
cnpm i --save-dev @types/react-resizable

CommonTable / index.tsx

import React, { useEffect, useMemo, useRef, useState, useCallback } from 'react';
import { createUseStyles } from 'react-jss';
import { Resizable } from 'react-resizable';
import { ColumnType } from 'antd/lib/table';
import { Table, Button } from 'antd';
import type { ButtonProps, TableProps } from 'antd';
import { useSize } from 'ahooks';export interface ICommonTableProps<RecordType> extends TableProps<RecordType> {onCreate?: () => void;onEdit?: () => void;deleteBtn?: {props?: ButtonProps;onDelete?: () => void;};isDrag?: boolean; // 控制table是否展示 可拖拽的表头
}
const useCommonTableStyles = createUseStyles({wrapper: {background: '#fff',marginTop: '12px',padding: '12px 12px'},header: {display: 'flex',marginTop: '8px',marginBottom: '20px'},tablActions: {display: 'flex',flex: 1,justifyContent: 'flex-end',alignItems: 'center'},headerBtn: {marginLeft: '16px'},resizableHandle : {position: 'absolute',right: '-5px',bottom: 0,zIndex: 1,width: '10px',height: '100%',cursor: 'col-resize'}
});// 表头拖拽组件
const ResizableTitle = (props: any ) => {
const { onResize, width, ...restProps } = propsconst classes = useCommonTableStyles();if (!width) { return (<th {...restProps} />) };return (<Resizablewidth={parseInt(width)}height={0}handle={<span className={classes.resizableHandle} onClick={e => { e.stopPropagation() }} />}onResize={onResize}draggableOpts={{ enableUserSelectHack: false }}><th {...restProps} style={{ ...restProps?.style, userSelect: 'none' }} /></Resizable>);
};export const CommonTable = <RecordType extends Record<string, any> = any>(props: ICommonTableProps<RecordType>
) => {const { onCreate, onEdit, deleteBtn, isDrag = true } = props;const classes = useCommonTableStyles();const wrapperRef = useRef<HTMLDivElement>(null);const bodyRef = useRef(document.body);const size = useSize(bodyRef);const [scroll, setScroll] = useState<TableProps<any>['scroll']>({ x: 'max-content' });const [rescolumns, setResColumns] = useState<ColumnType<RecordType>[]>(props.columns || []);const handleResize = (index: number): ((_: any, Resize: { size: { width: any } }) => void) => {return (_: any, Resize: { size: { width: any; }; }) => {const temp = [...rescolumns];temp[index] = { ...temp[index], width: Resize.size.width };setResColumns(temp);};};// 把 columns 用 map 重组为支持可拖拽的cellconst columnsMap: any[] = useMemo(() => {return (rescolumns?.map((column:any,index:any) => ({...column,onHeaderCell: (col: { width: any; }) => ({ width: col.width, onResize: handleResize(index) }),title: column.title,})) || []);}, [rescolumns]);useEffect(() => {if (wrapperRef.current) {const { top } = wrapperRef.current?.getBoundingClientRect();setScroll({x: 'max-content',y: innerHeight - top - 210});}}, [wrapperRef, size]);return (<div className={classes.wrapper} ref={wrapperRef}><div className={classes.header}><div className={classes.tablActions}>{onCreate && (<Button className={classes.headerBtn} type='primary' onClick={onCreate}>新增</Button>)}{onEdit && (<Button className={classes.headerBtn} type='default'>编辑</Button>)}{deleteBtn && (<Button{...deleteBtn.props}className={classes.headerBtn}type='default'dangeronClick={deleteBtn.onDelete}>删除</Button>)}</div></div><Table scroll={scroll} {...props} components={isDrag ? { header: { cell: ResizableTitle } } : undefined}columns={columnsMap}/></div>);
};

使用组件

import { createUseStyles } from 'react-jss';
import type { TableRowSelection } from 'antd/lib/table/interface';
import type { ColumnsType } from 'antd/lib/table';
import { useEffect, useMemo, useState, useRef } from 'react';
import { CommonTable } from '../components/CommonTable/index';const useStyles = createUseStyles({table: {background: '#fff',padding: '16px',marginTop: '16px',width: '100%',},textBtn: {color: '#0068FF',cursor: 'pointer',userSelect: 'none',},
});
const TablePage = () => {const [tableData, setTableData] = useState<any>([]);const [currentPage, setCurrentPage] = useState<number>(1);const [currentSize, setCurrentSize] = useState<number>(20);const classes = useStyles();const [tableLoading, setTableLoading] = useState(false);const [tableDataTotal, setTableDataTotal] = useState(0);const [selectedRow, setSelectedRow] = useState([] as any); //控制表格是否已选useEffect(() => {const resTable = [{ id: 1, type: 1, status: '草稿' },{ id: 2, type: 0, status: '已完成' },{ id: 3, type: 1, status: '草稿' },];setTableData(resTable);}, []);const rowSelection: TableRowSelection<any> = {onChange: (selectedRowKeys, selectedRows) => {setSelectedRow(selectedRowKeys);},};// 分页const handlePageChange = (page: number, size: number) => {setCurrentPage(page);setCurrentSize(size);// getList({ page, size, param: queryData }); // 获取table数据};const tableColumns: ColumnsType<any> = useMemo(() => {return [{title: '操作',dataIndex: 'code',fixed: 'left',width: '100px',render: (text, record) => (<divclassName={classes.textBtn}onClick={() => {console.log('onClick', text,"record",record);}}>{record['status'] === '草稿' ? '编辑' : '查看'}</div>),},{title: '序号',dataIndex: 'id',width: '60px',render: (_, __, index) => index + 1 + (currentPage - 1) * currentSize,},{title: '来源',dataIndex: 'type',// width: '130px', // 最后一个宽度不传render: (_, __, index) => (_ === 1 ? '系统' : '手工'),},];}, [classes.textBtn, currentPage, currentSize]);return (<><CommonTablerowKey={'id'}className={classes.table}columns={tableColumns}scroll={{x: 'max-content',}}pagination={{showTotal: () => `${tableDataTotal} 条记录`,onChange: (page, size) => handlePageChange(page, size),hideOnSinglePage: false,showQuickJumper: true,showSizeChanger: true,current: currentPage,pageSize: currentSize,total: tableDataTotal,}}dataSource={tableData}loading={tableLoading}rowSelection={rowSelection}/><CommonTablerowKey={'id'}isDrag={false}className={classes.table}columns={tableColumns}scroll={{x: 'max-content',}}pagination={{showTotal: () => `${tableDataTotal} 条记录`,onChange: (page, size) => handlePageChange(page, size),hideOnSinglePage: false,showQuickJumper: true,showSizeChanger: true,current: currentPage,pageSize: currentSize,total: tableDataTotal,}}dataSource={tableData}loading={tableLoading}rowSelection={rowSelection}/></>);
};
export default TablePage;

效果

在这里插入图片描述

2:useColumns组件

useColumns.tsx

import React, { useMemo, useCallback } from 'react';interface Args {handleEdit: (r: any) => void;handleSeeDetail: (r: any) => void;
}export const useColumns = ({ handleEdit, handleSeeDetail }: Args) => {const handleEvent = useCallback((v: string, record: any, e) => {e.stopPropagation();if (v === '编辑') {handleEdit(record);} else {handleSeeDetail(record);}},[handleSeeDetail, handleEdit],);// 渲染查看 || 编辑const showPop = useCallback((record: any) => {if (record.status === '1') {return (<spanonClick={(e) => handleEvent('编辑', record, e)}className="check-btn">编辑</span>);} else {return (<spanonClick={(e) => handleEvent('查看', record, e)}className="check-btn">查看</span>);}},[handleEvent],);const columnsData: any = useMemo(() => {const columns = [{title: '操作',width: '100px',fixed: 'left',render: (_: any, record: any) => showPop(record),},{title: '序号',width: '60px',render: (_: any, record: any, index: number) => `${index + 1}`,},{title: '名称',dataIndex: 'name',width: '130px',},{title: '年龄',dataIndex: 'age',},];return columns;}, [showPop]);return columnsData;
};export default useColumns;

使用

import { createUseStyles } from 'react-jss';
import type { TableRowSelection } from 'antd/lib/table/interface';
import type { ColumnsType } from 'antd/lib/table';
import { useEffect, useMemo, useState, useRef } from 'react';
import { CommonTable } from '../components/CommonTable/index';
import useColumns from "./useColumns"const useStyles = createUseStyles({table: {background: '#fff',padding: '16px',marginTop: '16px',width: '100%',},textBtn: {color: '#0068FF',cursor: 'pointer',userSelect: 'none',},
});
const TablePage = () => {const testData = [{ name: '测试1',age: 10 },{ name: '测试1',age: 20 },{ name: '测试1',age: 30 },]const handleSeeDetail = (row:any) => {console.log('查看', row);}const handleEdit = (row:any) => {console.log('编辑', row);}return (<><CommonTablerowKey={'id'}className={classes.table}dataSource={testData}scroll={{x: 'max-content',}}columns={useColumns({ handleSeeDetail, handleEdit })}/></>);
};
export default TablePage;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/2778898.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

系统架构24 - 软件架构设计(3)

软件架构风格&#xff08;上&#xff09; 概述架构风格数据流架构风格批处理风格管道-过滤风格 调用/返回架构风格主程序/子程序风格面向对象风格层次结构风格客户端/服务器风格 以数据为中心的架构风格仓库风格黑板风格 虚拟机架构风格解释器风格规则系统风格 独立构件架构风格…

React - 分页插件默认是英文怎么办

英文组件的通用解决方案 这里以分页插件为例&#xff1a; 大家可以看到&#xff0c;最后的这个页面跳转提示文字为Go to&#xff0c;不是中文&#xff0c;而官网里面的案例则是&#xff1a; 解决方案&#xff1a; import { ConfigProvider } from antd; import zhCN from an…

ShardingSphere 5.x 系列【7】元数据持久化

有道无术,术尚可求,有术无道,止于术。 本系列Spring Boot 版本 3.1.0 本系列ShardingSphere 版本 5.4.0 源码地址:https://gitee.com/pearl-organization/study-sharding-sphere-demo 文章目录 概述2. 单机模式2.1 H22.2 MySQL3. 集群模式3.1 ZooKeeper3.2 Nacos3.3 Cons…

【大厂AI课学习笔记】【1.5 AI技术领域】(10)对话系统

对话系统&#xff0c;Dialogue System&#xff0c;也称为会话代理。是一种模拟人类与人交谈的计算机系统&#xff0c;旨在可以与人类形成连贯通顺的对话&#xff0c;通信方式主要有语音/文本/图片&#xff0c;当然也可以手势/触觉等其他方式 一般我们将对话系统&#xff0c;分…

AES加密中的CBC和ECB

目录 1.说明 2.ECB模式&#xff08;base64&#xff09; 3.CBC模式 4.总结 1.说明 AES是常见的对称加密算法&#xff0c;加密和解密使用相同的密钥&#xff0c;流程如下&#xff1a; 主要概念如下&#xff1a; ①明文 ②密钥 用来加密明文的密码&#xff0c;在对称加密算…

C语言字符常量与字符变量..

1.字符常量 诸如’a’、‘b’、c’这类的都归属于字符常量 而且我们都知道printf()函数接收的第一个参数是字符串 所以不能够直接将字符常量作为printf函数的第一个参数 并且字符常量对应的占位符为%c 以下是对字符常量的演示 int main(){printf("%c%c%c%c", a, b…

第一篇【传奇开心果微博文系列】Python微项目技术点案例示例:pillow库实现毛笔字春联

传奇开心果微博文系列 系列微博文目录Python微项目技术点案例示例系列 微博文目录一、微项目目标二、实现微项目编程思路三、初步实现目标示例代码四、添加背景色、边框、阴影效果示例代码五、添加花纹背景、装饰线条示例代码六、添加花朵、插图等示例代码 系列微博文目录 Pyt…

Go语言每日一练——链表篇(八)

传送门 牛客面试笔试必刷101题 ----------------两个链表的第一个公共结点 题目以及解析 题目 解题代码及解析 解析 这一道题使用的还是双指针算法&#xff0c;我们先求出两个链表的长度差n&#xff0c;然后定义快慢指针&#xff0c;让快指针先走n步&#xff0c;最后快慢指…

【Linux】学习-进程信号

进程信号 信号入门 生活角度的信号 你在网上买了很多件商品,再等待不同商品快递的到来。但即便快递没有到来,你也知道快递来临时,你该怎么处理快递。也就是你能“识别快递”,也就是你意识里是知道如果这时候快递员送来了你的包裹,你知道该如何处理这些包裹当快递员到了你…

Javaweb之SpringBootWeb案例之事务管理的详细解析

1. 事务管理 1.1 事务回顾 在数据库阶段我们已学习过事务了&#xff0c;我们讲到&#xff1a; 事务是一组操作的集合&#xff0c;它是一个不可分割的工作单位。事务会把所有的操作作为一个整体&#xff0c;一起向数据库提交或者是撤销操作请求。所以这组操作要么同时成功&am…

区间dp 笔记

区间dp一般是先枚举区间长度&#xff0c;再枚举左端点&#xff0c;再枚举分界点&#xff0c;时间复杂度为 环形石子合并 将 n 堆石子绕圆形操场排放&#xff0c;现要将石子有序地合并成一堆。 规定每次只能选相邻的两堆合并成新的一堆&#xff0c;并将新的一堆的石子数记做该…

中创ET4410 台式LCR数字电桥 简单开箱测评

最近买了一台LCR电桥&#xff0c;完善一下自己实验室的设备&#xff0c;选了中创ET4410&#xff0c;这款性价比高一点。 1199元在PDD买的&#xff0c;好像胜利的VC4090C也是找中创代工的。 ET4410介绍 本系列LCR数字电桥是采用自动平衡电桥原理设计的元件参数分析仪&#xf…

JavaScript的聚焦:focus/blur

&#x1f9d1;‍&#x1f393; 个人主页&#xff1a;《爱蹦跶的大A阿》 &#x1f525;当前正在更新专栏&#xff1a;《VUE》 、《JavaScript保姆级教程》、《krpano》、《krpano中文文档》 ​ ​ ​ ✨ 正文 一、简介 focus 和 blur 事件是 HTML 元素的重要事件&#xff…

【大厂AI课学习笔记】【1.6 人工智能基础知识】(2)机器学习

目录 必须理解的知识点&#xff1a; 举一个草莓的例子&#xff1a; 机器学习的三个类别&#xff1a; 监督学习&#xff1a; 无监督学习&#xff1a; 强化学习&#xff1a; 更多知识背景&#xff1a; 机器学习的诞生需求 监督学习的关键技术与实现步骤 无监督学习的关…

AI-数学-高中-25-三角函数一三角函数对称性

原作者视频&#xff1a;【三角函数】【考点精华】3三角函数对称性&#xff08;重要&#xff09;&#xff08;中档&#xff09;_哔哩哔哩_bilibili 1.一个对称点\直线思路&#xff1a; 2.关于两点或两直线对称&#xff1a; 3.两个对称&#xff1a;一个关于点对称、一个关于直线…

剑指offer——替换空格

目录 1. 题目描述与背景1.1 题目描述1.2 背景 2. 一般思路 &#xff08;时间复杂度为O(n)&#xff09;3. 分析4. 完整代码4.1 标准答案 1. 题目描述与背景 1.1 题目描述 请实现一个函数&#xff0c;把字符串中的每个空格替换成 “ %20 ” 。例如&#xff1a;输入“ we are hap…

C#计算矩形面积:通过定义结构 vs 通过继承类

目录 一、涉及到的知识点 1、结构 2.结构和类的区别 3.继承 4.使用类继承提高程序的开发效率 二、实例&#xff1a;通过定义结构计算矩形面积 1.源码 2.生成效果 三、实例&#xff1a;通过继承类计算梯形面积 1.源码 2.生成效果 一、涉及到的知识点 1、结构 结构是…

我主编的电子技术实验手册(04)——电压的测量与接地

本专栏是笔者主编教材&#xff08;图0所示&#xff09;的电子版&#xff0c;依托简易的元器件和仪表安排了30多个实验&#xff0c;主要面向经费不太充足的中高职院校。每个实验都安排了必不可少的【预习知识】&#xff0c;精心设计的【实验步骤】&#xff0c;全面丰富的【思考习…

linux学习之虚拟地址

在以往的学习中我们经常接触地址&#xff0c;电脑像一个小房间&#xff0c;它的空间是有限不可重叠的&#xff0c;但是可以覆盖。想象一下如果我们要放很多东西进去&#xff0c;如果没有合理的安排&#xff0c;所有东西乱放&#xff0c;那么我们需要寻找某一个东西的时候需要把…

【从Python基础到深度学习】2. Ubuntu及插件安装

本期所有软件安装包&#xff1a;链接&#xff1a;https://pan.baidu.com/s/1UVEYm-12FivAnrE5NUXevg?pwdum60 一、安装Ubuntu 1.1 软件安装包&#xff1a;下载 VMware Workstation Pro | CN 一直点下一步即可 1.2 双击运行软件&#xff1a; 输入密钥 1 、VMware 15密钥 …