antd 二次封装table

592 阅读1分钟

项目地址:gitee.com/lihuikun1/r…

首先是table有多个按钮可以从外界传入,使用的是tsx的children进行插槽 关键代码

interface EditableCellProps {
        ...
	//插槽的ts类型校验
	children?: React.ReactNode;
}

const EditableTable: React.FC<EditableTableProps> = ({
	...
	children
}) => {
    <>
        <span>
            <Button type="primary" onClick={handleAdd} style={{ marginBottom: 16 }}>
		<PlusOutlined /> Add Row
            </Button>
           {/* 遍历传入的插槽,判断是不是react的节点,不是就返回child,是就渲染节点 */}
            {React.Children.map(children, (child, index) => {
		if (React.isValidElement(child)) {
                    return React.cloneElement(child, {key: `slot-${index}`,style: { marginLeft: "10px" } // 可以为插槽添加样式
		} as React.HTMLAttributes<HTMLElement> & { style: CSSProperties });
		}
		return child;
            })}
	</span>
}

父组件使用

<EditableTable>
    <Button type="primary" onClick={() => handleTableChange({}, {}, {})} style={{ marginBottom: "10px", width: "100px" }}>刷新</Button>
</EditableTable>

antd的数据源是key作为唯一的key,如果数据是id,可以将ttable指定为这样<Table rowKey="id"/>

setDataSource([
        //官方的代码的数据源是key:1,想改为id,如上设置即可
	{ id: 1, name: "John Brown", age: 32, address: "New York No. 1 Lake Park" },
	{ id: 2, name: "Jim Green", age: 42, address: "London No. 1 Lake Park" },
	{ id: 3, name: "Joe Black", age: 32, address: "Sidney No. 1 Lake Park" }
]);

完整的代码

import React, { CSSProperties, useState, useEffect } from "react";
import { Table, Button, Modal, Form, Input } from "antd";
import { PlusOutlined } from "@ant-design/icons";
interface EditableTableProps {
	columns: any[];
	dataSource: any[];
	loading: boolean;
	total: number;
	onChange: (pagination: any, filters: any, sorter: any) => void;
	onDelete: (record: any) => void;
	onAdd: (dataSource: any) => void;
	children: React.ReactNode;
}
interface Info {
	id?: number | string;
	title?: string;
	age?: number;
	address?: string;
}
const EditableTable: React.FC<EditableTableProps> = ({
	columns,
	dataSource,
	loading,
	total,
	onChange,
	onDelete,
	onAdd,
	children
}) => {
	const [form] = Form.useForm();
	const [data, setData] = useState<any[]>(dataSource);
	const [visible, setVisible] = useState(false);
	// 判断是add还是edit
	const [actionType, setActionType] = useState("");
	// 将其他的信息临时存到info变量里面
	const [info, setInfo] = useState<Info>({});

	useEffect(() => {
		//获取父组件传过来的data,关闭弹窗清空变量
		setData(dataSource);
		if (!visible) {
			setInfo({});
		}
	}, [dataSource, visible]);

	const edit = (record: any) => {
		setVisible(true);
		setInfo(record);
		form.setFieldsValue({ ...record });
		setActionType("edit");
	};

	const handleDelete = (record: any) => {
		const newData = [...data];
		const index = newData.findIndex(item => record.id === item.id);
		console.log("newData", newData, record, index);
		if (index > -1) {
			newData.splice(index, 1);
			setData(newData);
			onDelete(record);
		}
	};

	const handleAdd = () => {
		console.log("form", form);
		setVisible(true);
		setActionType("add");
	};

	const handleOk = () => {
		console.log("setData(dataSource);", form.getFieldsValue());
		console.log("values", form);

		form.submit();
	};

	const handleCancel = () => {
		setVisible(false);
	};

	const handleFinish = (values: any, actionType: string) => {
		const newData = [...data];
		if (actionType === "add") {
			newData.push({ id: (newData.length + 1) as number, ...values });
		} else if (actionType === "edit") {
			// 根据数据的 id 查找要编辑的数据,并更新它的值
			const index = newData.findIndex(item => item.id === info.id);
			if (index > -1) {
				newData[index] = {
					id: info.id,
					...values
				};
			}
		}
		setData(newData);
		onAdd(newData);
		// 清空表单
		form.resetFields();
		setVisible(false);
	};
	const handleTableChange = (pagination: any, filters: any, sorter: any) => {
		onChange(pagination, filters, sorter);
	};

	const columnsWithEditAndDelete = [
		...columns,
		{
			title: "Action",
			dataIndex: "action",
			render: (_: any, record: any) => {
				return (
					<span>
						<Button type="link" onClick={() => edit(record)} style={{ marginRight: 8 }}>
							Edit
						</Button>
						<Button type="link" danger onClick={() => handleDelete(record)}>
							Delete
						</Button>
					</span>
				);
			}
		}
	];

	return (
		<>
			<span>
				<Button type="primary" onClick={handleAdd} style={{ marginBottom: 16 }}>
					<PlusOutlined /> Add Row
				</Button>
				{/* 遍历传入的插槽,判断是不是react的节点,不是就返回child,是就渲染节点 */}
				{React.Children.map(children, (child, index) => {
					if (React.isValidElement(child)) {
						return React.cloneElement(child, {
							id: `slot-${index}`,
							style: { marginLeft: "10px" } // 可以为插槽添加样式
						} as React.HTMLAttributes<HTMLElement> & { style: CSSProperties });
					}
					return child;
				})}
			</span>

			<Table
				columns={columnsWithEditAndDelete}
				dataSource={data}
				loading={loading}
				pagination={{
					total: total,
					showSizeChanger: true,
					showQuickJumper: true
				}}
				onChange={handleTableChange}
				rowKey="id"
			/>
			{/* Warning: Instance created by useForm is not connected to any Form element. Forget to pass form prop? */}
			{/* 页面初始化,调用 form 方法时,因为 Modal 还未初始化,导致 form 这时候还没有挂载的 element,这时候调用form的方法就会报错, 此时 form 没有关联任何 Form 组件。 */}
			{/* 解决方法: getContainer={false} */}
			<Modal visible={visible} getContainer={false} title="Add New Row" onCancel={handleCancel} onOk={handleOk} destroyOnClose>
				<Form form={form} onFinish={values => handleFinish(values, actionType)}>
					{columns.map(column => (
						<Form.Item
							key={column.dataIndex}
							name={column.dataIndex}
							label={column.title}
							rules={[
								{
									required: true,
									message: `Please enter ${column.title}!`
								}
							]}
						>
							{column.inputType === "number" ? <Input type="number" /> : <Input />}
						</Form.Item>
					))}
				</Form>
			</Modal>
		</>
	);
};

export default EditableTable;