Хотите узнать как сделать подобное? Тогда эта статья для вас! :)
И так что вы узнаете из этой статьи:
- Введение
- Мнение о React-beautiful-dnd (-)
- Мнение о Dragula.js (-)
- Мнение о Draggable от shopify (-)
Введение
Перед Вами стоит задача используя компонент Table из набора material-ui, сделать таблицу со строками, в которой, так прям удобненько, кликом и перетягиванием, можно менять положение строк.
Начну с того что оговорюсь, задача это не тривиальная, особенно в нашем бурно развивающемся мире. Куча всяких библиотек для drag-n-drop. Большая часть из которых, либо самостоятельные, либо привязаны к jQuery (куда же без него). Для React есть несколько библиотек, а также присутствуют врапперы (недореакт библиотеки).
Приведу в пример, какие библиотеки мне попадались.
Мнение о React-beautiful-dnd (-)
И так начнем с той, что посоветовали — это react-beautiful-dnd. Вроде как сделана ребятами из atlassian (серьезные такие (прожженные зеленые шершни) мужики, авторы всемирно известных продуктов среди разработчиков). Но помочь она мне не смогла, давайте посмотрим почему:
Минусы
- Во-первых она заточена под листы и только листы, которые состоят из одних дивов. Если вы захотите обрамить <tr> в таблице, то увы, у вас этого не получится. В противном случае придется делать таблицу на дивах и это ух как нежелательно, ведь тогда можно забыть о компоненте Table material-ui.
- Нет встроенной прокрутки, ребята не дают этого по умолчанию в своей либе.
- Если используется React 15.6.X то как говорится мечтать о возврате плейсхолдера и одновременно компонента <tr> не приходится. React 15 не поддерживает возврат массива элементов.
Обходные пути для таблицы
- Можно воспользоваться возможностями React 16, как к примеру тут в этом примере https://www.webpackbin.com/bins/-KvU70fxM3VdlP_ND0Zv. Ну и приложу issue, в котором была найдена ссылка на этот вид обхода https://github.com/atlassian/react-beautiful-dnd/issues/103. Но увы, текущая версия material-ui не может так быстро перекатиться на React 16. Потому облом. Да и не стоит этих усилий это решение.
Плюсы конечно есть, но в рамках моей задачи их не оказалось.
Мнение о Dragula.js (-)
Вот как бы тоже библиотека, но посмотрев на её синтаксис и неудобство использования, сразу же отказался мысли использовать её, мне все хотелось, легкости и неповторимости и простоты прежде всего. В этой либе, этого к сожалению не обнаружил. Решил её упомянуть, может кому пригодится. Еще мне очень понравился логотип :).
Мнение о Draggable от shopify (-)
Вот тут сия классная и прикольная библиотека находится https://shopify.github.io/draggable/. Но она к сожалению не реактовая и как то создавать враппер и мучиться с рефами не очень то хотелось. Привожу её тут только потому что она встретилась мне на пути и еще о ней упоминали в канале по фронтенду в телеграмме. И она мне показалось прикольной.
Народ поднял тему по поводу интеграции с React https://github.com/Shopify/draggable/issues/34. Вроде как Shopify собираются делать свой редактор на React и обещают заинтегрить эту либу соотвественно. Ждемс ждемс :)
Мнение о react-sortable-hoc (+) — спаситель!!!
Ну вот, наконец-то и дошли мы до самой вкусной части! Эта библиотека буквально вытащила меня из уныния и болота дивных таблиц! Я очень очень рад, что нашел её на просторах интернета.
Почему её нужно использовать? (от авторов)
Уже есть множество отличных библиотек Drag & Drop (например, react-dnd — он конечно же фантастический). Если эти библиотеки соответствуют вашим потребностям, вы должны сначала дать им шанс. Однако большинство этих библиотек полагаются на API-интерфейс Drag & Drop HTML5, который имеет некоторые серьезные ограничения. Например, вещи быстро становятся сложными, если вам нужно поддерживать сенсорные устройства, если вам нужно заблокировать перетаскивание по оси или если вы хотите анимировать узлы по мере их сортировки. React Sortable HOC нацелен на предоставление простого набора компонентов более высокого порядка для заполнения этих пробелов. Если вы ищете простой, удобный для мобильных устройств, способ добавить сортировку в свои списки, то вы идете в нужном направлении.
Плюсы
- Легка в использовании, так как использует нехнологию Hight Order Component. Она как бы оборачивает ваш компонент и наделяет его силой.
- Не перекладывает на пользователя ответственность за возврат и размещение плейсхолдера.
- Не создает врапперов дополнительных над вашим компонентом.
- Можно легко поменять область захвата для того чтобы сделать возможным drag-n-drop при нажатии на определенной области (к примеру какой нибудь маркер в виде иконки). По умолчанию весь компонент является активной областью для активации драг-н-дропа. Используется HOC SortableContainer c установленным свойством useDragHandle.
- Легко можно выключить возможность drag-n-drop используя свойство disabled у компонента SortableElement.
В общем все, что нужно, для решения моей задачи. Но честно говоря, были конечно сомнения, по поводу, получится или нет помирить эту либу с material-ui.
Так вот как я шел к решению задачи:
- Сначала надо конечно же установить её
- Далее нужно подготовить компоненты, создадим Row который будем использовать с оберткой в SortableElement
- Создать кастомный TableBody, да так чтобы material-ui ничего не заподозрил :). Используется вот такой финт с muiName
- Добавить DragHandle компонент, если нужно ограничить область активации drag-n-drop. При этом нужно нашему SortableTableBody указать свойство useDragHandle.
- Объединить все во едино и мы получаем таблицу с поддержкой drag-n-drop изменения позиции строк.
Код Sortable Table material-ui
От себя: Хочу выразить огромное спасибо авторам этой библиотеки. Они сделали именно все профессионально и я не увидел строгой привязки каких либо свойств, связанных с коллекцией элементов или самим элементом. Профи делаю все так, что код выполняет свою функцию ровно на столько, на сколько это нужно и возможно. Полное разделение ответственностей и я скажу честно - это один из немногих подходов, который очень мне понравился.
Хотелось бы чтобы все остальные разработчики делали действительно удобные библиотеки! Без лимитов и проблем!
Ранее эта статья была опубликована тут.