react-beautiful-dnd ドラッグ&ドロップで順序を入れ替える

参考にした記事

<DragDropContext />
ドラッグできる要素とドロップできる範囲を指定する。
最上位に置くこと。
onDragEnd
onDragEnd関数を設定してドロップ後のリスト内のアイテムの順番を保持する。
<Droppable />
ドラッグした要素をドロップする範囲を指定する。
指定した範囲外にドロップした場合は順序は入れ替わらない。
droppableId
ライブラリが特定のDroppableインスタンスを追跡できるように追加する必要がある。
string型で指定する。
provided
provided引数を渡す関数をラップする必要があり、引数の値を元にどの要素がどの位置に移動されたかをトラッキングする。
snapshot
ドラッグ&ドロップ中のコンポーネントの状態を返してくれるもの。
プロパティは以下を持っている。
- isDraggingOver
- draggingOverWith
- draggingFromThisWith
- isUsingPlaceholder
<Draggable />
ドラッグしたい要素をラップする。
draggableId
ライブラリが特定のDraggableインスタンスを追跡できるように追加する必要がある。
string型で指定する。
snapshot
プロパティは以下を持っている。
- isDragging
- isDropAnimating
- dropAnimation
- draggingOver
- combineWith
- combineTargetFor
- mode
placeholder
Droppableの下に{provided.placeholder}を追加する。
追加することでドラッグしたアイテムがドラッグされる前に使っていたスペースを埋めてくれる。

Table内で使用する場合
Table内でreact-beautiful-dndを使用する場合は注意が必要である。
TableRowをドラッグした際のデザインが崩れてしまう可能性がある。
理由は元々の親要素からスタイルが外れてしまう可能性があるからである。
今回は実際にドラッグ中にスタイルが崩れてしまったので、解決策を記録しておく。
開発環境
- material-ui v4
- Table
- react-beautiful-dnd v13.1.0
解決策
親要素からスタイルが外れてしまうため、TableHeadのTableRow配下にあるTableCellの横幅をそれぞれ取得して、その横幅をTableBodyのTableRow配下にあるTableCellにそれぞれ横幅をセットすると崩れなくなる。
const [cellWidthList, setCellWidthList] = useState<number[]>([]);
const updateCellWidth = () => {
const rowElm = document.getElementById("{TableHeadのTableRowのID}"); // table-head-rowなど
if (!rowElm) return;
const rowChildren = rowElm.children;
const result = []; // number[]
rowChildren.forEach((child) => {
result.push(child.clientWidth);
})
setCellWidthList(result);
};
cellWidthListを配列順にTableBodyのTableRow配下にあるTableCellにセットすればOK!!
##レスポンシブ対応
上記の解決策でスタイルが崩れることがなかったが、レスポンシブ対応を含めると以下のコードも必要である。
useEffect(() => {
updateCellWidth();
window.addEventListener('resizeMainArea', updateCellWidth);
return () => window.removeEventListener('resizeMainArea', updateCellWidth);
},[]);