#reactjs #react-beautiful-dnd
Вопрос:
Я новичок и в настоящее время пытаюсь научиться делать строки таблицы перетаскиваемыми и переставляемыми. Я использую библиотеку react-beautiful-dnd. Мне удалось сделать строки перетаскиваемыми, но я не могу сохранить состояние строк после перетаскивания. Я был бы признателен за любую помощь в этом вопросе.
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:
(1) Прежде всего, сохраните список элементов в состоянии компонента и сделайте строки таблицы динамичными. Помимо того, что это более СУХО, это позволит вам повторно отображать строки таблицы каждый раз, когда меняется порядок списка:
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 };
}
Чем вы создадите свой <Draggable>
список таким образом:
{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) Добавьте onDragEnd
обработчик событий. Обработчик получит объект с некоторой полезной информацией, особенно идентификатором перетаскиваемого элемента, назначения и источника, и будет использовать эту информацию для изменения порядка списка:
onDragEnd = e => {
...
};
...
<DragDropContext onDragEnd={this.onDragEnd}>...</DragDropContext>
(3) Напишите функцию для изменения порядка списка. Обратите внимание, что функция должна возвращать новый массив (а не просто изменять существующий), чтобы вы могли сохранить его в состоянии компонента. Вот пример:
reorder = (list, startIndex, endIndex) => {
const result = Array.from(list);
const [removed] = result.splice(startIndex, 1);
result.splice(endIndex, 0, removed);
return resu<
};
(4) onDragEnd
вызовет reorder
функцию, чтобы получить новый, упорядоченный массив и сохранить его в состоянии компонента. Это приведет к повторному отправке таблицы. Здесь весь обновленный компонент:
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 resu<
};
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>
);
}
}
Рабочий стекблитц
Комментарии:
1. @Hawra Saif Я только что понял, что в своем ответе я изменил компонент вашего класса на компонент функции… Надеюсь, для вас это не проблема.
2. Спасибо за решение. Но мне нужно реализовать его как компонент класса, и единственное, что здесь будет иметь значение, — это хук useState, поскольку он не может использоваться в компонентах класса. Итак, каким может быть обходной путь для этого?
3. Обновил ответ как компонент класса. И Стакблитц тоже.
4. Большое спасибо! Ваше решение помогло мне понять многое.
5. Рад помочь. Пожалуйста, подумайте о том, чтобы принять ответ, если он решит вашу проблему.