import React, { useCallback, useRef, useState } from 'react'; import { Table } from 'antd'; import type { ColumnsType } from 'antd/es/table'; import update from 'immutability-helper'; import { DndProvider, useDrag, useDrop } from 'react-dnd'; import { HTML5Backend } from 'react-dnd-html5-backend'; interface DataType { key: string; name: string; age: number; address: string; } interface DraggableBodyRowProps extends React.HTMLAttributes { index: number; moveRow: (dragIndex: number, hoverIndex: number) => void; } const type = 'DraggableBodyRow'; const DraggableBodyRow = ({ index, moveRow, className, style, ...restProps }: DraggableBodyRowProps) => { const ref = useRef(null); const [{ isOver, dropClassName }, drop] = useDrop({ accept: type, collect: (monitor) => { const { index: dragIndex } = monitor.getItem() || {}; if (dragIndex === index) { return {}; } return { isOver: monitor.isOver(), dropClassName: dragIndex < index ? ' drop-over-downward' : ' drop-over-upward', }; }, drop: (item: { index: number }) => { moveRow(item.index, index); }, }); const [, drag] = useDrag({ type, item: { index }, collect: (monitor) => ({ isDragging: monitor.isDragging(), }), }); drop(drag(ref)); return ( ); }; const columns: ColumnsType = [ { title: 'Name', dataIndex: 'name', key: 'name', }, { title: 'Age', dataIndex: 'age', key: 'age', }, { title: 'Address', dataIndex: 'address', key: 'address', }, ]; const App: React.FC = () => { const [data, setData] = useState([ { key: '1', name: 'John Brown', age: 32, address: 'New York No. 1 Lake Park', }, { key: '2', name: 'Jim Green', age: 42, address: 'London No. 1 Lake Park', }, { key: '3', name: 'Joe Black', age: 32, address: 'Sydney No. 1 Lake Park', }, ]); const components = { body: { row: DraggableBodyRow, }, }; const moveRow = useCallback( (dragIndex: number, hoverIndex: number) => { const dragRow = data[dragIndex]; setData( update(data, { $splice: [ [dragIndex, 1], [hoverIndex, 0, dragRow], ], }), ); }, [data], ); return ( { const attr = { index, moveRow, }; return attr as React.HTMLAttributes; }} /> ); }; export default App;