React

SortableJS — это мощная библиотека для создания интерактивных списков с перетаскиванием элементов. Для работы в React рекомендуется использовать официальный обёртку react-sortablejs, которая обеспечивает удобное связывание состояния компонентов с действиями пользователя.

Установка через npm:

npm install sortablejs react-sortablejs

Подключение в компоненте:

import React, { useState } from 'react';
import Sortable from 'react-sortablejs';

Основы использования

SortableJS работает на основе DOM-элементов, поэтому при интеграции с React ключевым моментом является синхронизация состояния компонента с порядком элементов в списке. Это достигается хранением массива элементов в useState и обновлением его при событии onChange.

Пример базового списка:

const App = () => {
  const [items, setItems] = useState(['Элемент 1', 'Элемент 2', 'Элемент 3']);

  return (
    <Sortable
      tag="ul"
      onCha nge={(order, sortable, evt) => setItems(order)}
    >
      {items.map(item => (
        <li key={item}>{item}</li>
      ))}
    </Sortable>
  );
};

Особенности этого подхода:

  • tag задаёт HTML-тег контейнера.
  • onChange получает новый порядок элементов в виде массива.
  • Каждый элемент списка должен иметь уникальный key.

Настройка опций

SortableJS поддерживает множество опций, позволяющих управлять поведением списка:

  • animation — скорость анимации при перемещении элементов.
  • group — позволяет объединять несколько списков для перетаскивания между ними.
  • disabled — отключает сортировку.
  • handle — задаёт селектор для перетаскиваемой области.
  • ghostClass — класс, применяемый к элементу во время перетаскивания.

Пример с опциями:

<Sortable
  tag="ul"
  animation={150}
  handle=".drag-handle"
  ghostClass="dragging"
  onCha nge={(order) => setItems(order)}
>
  {items.map(item => (
    <li key={item}>
      <span className="drag-handle">☰</span> {item}
    </li>
  ))}
</Sortable>

Работа с несколькими списками

С помощью опции group можно создавать взаимодействующие списки, позволяя перемещать элементы между ними.

const [listA, setListA] = useState(['A1', 'A2', 'A3']);
const [listB, setListB] = useState(['B1', 'B2', 'B3']);

<Sortable
  tag="ul"
  group="shared"
  onCha nge={setListA}
>
  {listA.map(item => <li key={item}>{item}</li>)}
</Sortable>

<Sortable
  tag="ul"
  group="shared"
  onCha nge={setListB}
>
  {listB.map(item => <li key={item}>{item}</li>)}
</Sortable>

Ключевой момент — одинаковое имя группы для взаимодействующих списков. При перемещении элемент автоматически удаляется из одного массива и добавляется в другой.

Поддержка сложных компонентов

SortableJS может работать не только с простыми строками, но и с компонентами React с собственными состояниями. Для корректной работы нужно использовать уникальные идентификаторы в key, а порядок элементов хранить в состоянии.

const tasks = [
  { id: 1, text: 'Сделать задачу 1' },
  { id: 2, text: 'Сделать задачу 2' }
];

const [taskList, setTaskList] = useState(tasks);

<Sortable
  tag="ul"
  onCha nge={(order, sortable) => {
    const sortedTasks = order.map(id => taskList.find(task => task.id.toString() === id));
    setTaskList(sortedTasks);
  }}
>
  {taskList.map(task => (
    <li key={task.id}>{task.text}</li>
  ))}
</Sortable>

Обработка событий

SortableJS предоставляет множество событий для тонкой настройки взаимодействия:

  • onStart — начало перетаскивания.
  • onEnd — завершение перетаскивания.
  • onAdd — элемент добавлен из другого списка.
  • onRemove — элемент удалён в другой список.
  • onSort — порядок элементов изменён.

Пример логирования событий:

<Sortable
  tag="ul"
  onSt art={() => console.log('Перетаскивание начато')}
  on End={() => console.log('Перетаскивание завершено')}
  on Add={(evt) => console.log('Добавлен элемент', evt.item)}
  onRem ove={(evt) => console.log('Удалён элемент', evt.item)}
>
  {taskList.map(task => <li key={task.id}>{task.text}</li>)}
</Sortable>

Интеграция с формами и сохранение состояния

SortableJS легко интегрируется с формами, сохраняя порядок элементов при отправке данных. Можно хранить массив идентификаторов и отправлять его на сервер.

const handleSubmit = () => {
  const order = taskList.map(task => task.id);
  fetch('/save-order', {
    method: 'POST',
    body: JSON.stringify({ order }),
    headers: { 'Content-Type': 'application/json' }
  });
};

Оптимизация производительности

  • Использовать React.memo для элементов списка с большим количеством данных.
  • Ограничивать количество вызовов setState через onChange — можно применять debounce.
  • Для длинных списков рекомендуется использовать виртуализацию совместно с библиотекой SortableJS.

Работа с условной сортировкой

Можно динамически включать или отключать сортировку через disabled:

const [sortableEnabled, setSortableEnabled] = useState(true);

<Sortable
  tag="ul"
  disabled={!sortableEnabled}
>
  {items.map(item => <li key={item}>{item}</li>)}
</Sortable>

Переключение состояния позволяет создавать интерактивные интерфейсы с включаемой и выключаемой сортировкой.

Пользовательские стили и анимация

SortableJS поддерживает кастомизацию через CSS-классы:

  • .sortable-ghost — элемент-призрак при перетаскивании.
  • .sortable-chosen — выбранный элемент.
  • .sortable-drag — элемент, который перемещается в данный момент.

Пример CSS:

.dragging {
  opacity: 0.5;
  background-color: #f0f0f0;
}
.drag-handle {
  cursor: grab;
}

Анимация задаётся опцией animation в миллисекундах, что обеспечивает плавное перемещение элементов.


SortableJS в сочетании с React обеспечивает гибкую и мощную платформу для создания интерактивных списков, позволяя интегрировать перетаскивание с состоянием приложения, несколькими списками и кастомными компонентами. Правильная работа с ключами, состоянием и событиями делает взаимодействие пользователя плавным и предсказуемым.