I am a beginner and currently, I am trying to learn how to make the rows of the table draggable and rearrangable. I am using the react-beautiful-dnd library. I was able to make the rows draggable but I am not able to save the state of the rows after dragging and dropping. I would appreciate any help regarding this.
import { Component } from 'react';
import React from 'react';
import './App.css';
import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd';
class App extends Component
{
drawTable = () => {
return (
<div>
<DragDropContext>
<Droppable droppableId="Table">
{(provided) => (
<table {...provided.droppableProps} ref={provided.innerRef}>
<Draggable draggableId='1' index={1}>
{(provided) => (
<tr ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}>
<td>1</td>
<td>Mark</td>
<td>Otto</td>
<td>@mdo</td>
</tr>
)}
</Draggable>
<Draggable draggableId='2' index={2}>
{(provided) => (
<tr ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}>
<td>2</td>
<td>Jacob</td>
<td>Thornton</td>
<td>@fat</td>
</tr>
)}
</Draggable>
<Draggable draggableId='3' index={3}>
{(provided) => (
<tr ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}>
<td>3</td>
<td>Larry the Bird</td>
<td>@twitter</td>
</tr>
)}
</Draggable>
{provided.placeholder}
</table>
)}
</Droppable>
</DragDropContext>
</div>
);
}
render = () => {
return (
<div>
{this.drawTable()}
</div>
);
}
}
export default App;
(1) First of all, store your item list in a component state and make your table rows dynamic. Beside being more DRY that will allow you to re-render the table rows each time the list order changes:
startingList = [
{
id: '1',
fName: 'Mark',
lName: 'Otto'
},
{
id: '2',
fName: 'Jacob',
lName: 'Thornton'
},
{
id: '3',
fName: 'Larry',
lName: 'Bird'
}
];
constructor(props) {
super(props);
this.state = { items: this.startingList };
}
Than you create your <Draggable>
list like this:
{this.state.items.map((item, index) => (
<Draggable key={item.id} draggableId={item.id} index={index}>
{provided => (
<tr
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
>
<td>{item.id}</td>
<td>{item.fName}</td>
<td>{item.lName}</td>
</tr>
)}
</Draggable>
))}
(2) Add onDragEnd
event handler. The handler will receive an object with some useful information, especially id of the dragged item, destination and source, and will use that information to reorder the list:
onDragEnd = e => {
...
};
...
<DragDropContext onDragEnd={this.onDragEnd}>...</DragDropContext>
(3) Write a function to reorder the list. Note that the function shall return a new array (not just change the existing one), so that you can store that in the component state. Here's an example:
reorder = (list, startIndex, endIndex) => {
const result = Array.from(list);
const [removed] = result.splice(startIndex, 1);
result.splice(endIndex, 0, removed);
return result;
};
(4) onDragEnd
will call the reorder
function to get a new, reorderd array and store it in the component state. That will cause the table to rerender. Here the whole updated component:
class App extends React.Component {
startingList = [
{
id: '1',
fName: 'Mark',
lName: 'Otto'
},
{
id: '2',
fName: 'Jacob',
lName: 'Thornton'
},
{
id: '3',
fName: 'Larry',
lName: 'Bird'
}
];
constructor(props) {
super(props);
this.state = { items: this.startingList };
}
onDragEnd = e => {
console.log(e);
if (!e.destination) {
return;
}
const { items } = this.state;
const sorted = this.reorder(items, e.source.index, e.destination.index);
console.log(sorted);
this.setState({
items: sorted
});
};
reorder = (list, startIndex, endIndex) => {
const result = Array.from(list);
const [removed] = result.splice(startIndex, 1);
result.splice(endIndex, 0, removed);
return result;
};
render() {
return (
<div>
<DragDropContext onDragEnd={this.onDragEnd}>
<Droppable droppableId="Table">
{provided => (
<table {...provided.droppableProps} ref={provided.innerRef}>
<tbody>
{this.state.items.map((item, index) => (
<Draggable
key={item.id}
draggableId={item.id}
index={index}
>
{provided => (
<tr
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
>
<td>{item.id}</td>
<td>{item.fName}</td>
<td>{item.lName}</td>
</tr>
)}
</Draggable>
))}
{provided.placeholder}
</tbody>
</table>
)}
</Droppable>
</DragDropContext>
</div>
);
}
}
Working stackblitz