Как сохранить состояние строк перетаскивания в React?

#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. Рад помочь. Пожалуйста, подумайте о том, чтобы принять ответ, если он решит вашу проблему.