dnd-kit を使って複数のリスト間でドラッグ&ドロップを実現する場合のメモ
複数リストで考慮すべきポイント
- 各リストごとに
SortableContextを用意する - アイテムの
idがリスト間で重複しないように設計する onDragEndで「どのリストからどのリストへ移動したのか」を判定する- 並び替えだけでなく、リスト間移動も考慮した状態管理を行う
プレフィックス付きID設計
リスト間でアイテムの id が重複する可能性がある場合、リストごとにプレフィックスを付与することで管理しやすくなる
重複していると反応しないので、つけておいた方が良い
実装例
<DndContext onDragEnd={handleDragEnd}> <div style={{ display: 'flex', gap: '20px' }}> {lists.map(list => ( <SortableContext key={list.id} items={list.items} strategy={verticalListSortingStrategy}> <div> <h3>{list.title}</h3> {list.items.map(itemId => ( <SortableItem key={itemId} id={itemId} /> ))} </div> </SortableContext> ))} </div> </DndContext>
onDragEnd の実装ポイント
リスト間でアイテムが移動した場合、以下のように判定する
const handleDragEnd = (event) => { const { active, over } = event; if (!over) return; const fromList = findListByItemId(active.id); const toList = findListByItemId(over.id); if (!fromList || !toList) return; if (fromList.id === toList.id) { // 同一リスト内の並び替え reorderWithinList(fromList, active.id, over.id); } else { // リスト間移動 moveItemToAnotherList(fromList, toList, active.id, over.id); } };
状態管理の例
const [lists, setLists] = useState([ { id: 'list-a', title: 'リストA', items: ['a-1', 'a-2'] }, { id: 'list-b', title: 'リストB', items: ['b-1'] }, ]);
リストごとにアイテム配列を保持し、移動時に適切に更新する
よくある課題と対応策
| 課題 | 対応策 |
|---|---|
| ID 重複によるバグ | プレフィックスを付与する |
| 空のリストにドロップできない | リスト全体に useDroppable を適用 |
| ドロップ先の判定が曖昧になる | collisionDetection を調整する |
| ドラッグ中の見た目が崩れる | DragOverlay を適切に設定する |