並び替え可能な要素(Sortable)の中に、さらに並び替え可能な要素(Sortable)を配置したい
例えば、Torello のような、カードリスト内も並び替えできるし、リスト自体も並び替えられるようなケース
実装した時に、つまづいたことなどを整理する
基本構成
Sortable なアイテムの内部に、useSortable を使ってさらに並び替え可能な要素を定義することは可能だった
ただ、いくつか注意点があった
例
function SortableItem({ id }) { const { setNodeRef, attributes, listeners } = useSortable({ id }); return ( <div ref={setNodeRef} {...attributes} {...listeners}> <div>並び替え可能なコンテンツ</div> <DroppableArea id={`drop-${id}`} /> </div> ); } function DroppableArea({ id }) { const { setNodeRef, isOver } = useSortable({ id }); return ( <div ref={setNodeRef} style={{ background: isOver ? '#d0f0ff' : '#f5f5f5' }}> ドロップエリア </div> ); }
注意点1: event.over が期待通りに動かない場合がある
別のリストへのカードのドラッグでは、 event.over が親の Sortable に反応するのか、内側の Sortable に反応するのか不安定な挙動になる
なので、onDragEnd での処理は、両方の可能性を考えて実装が必要
もしくは、collisionDetection を自前で設定する必要がある
注意点2: リスト間で id が重複してバグる
2つのuseSortableのそれぞれに渡すidは重複してはならないが、設計上ならないはずが万が一データ不備で重複した場合、DnDが機能しなくなる
理由がわかるまで時間を費やしてしまったので、一意性が保証するためそれぞれに プレフィックスをつけておくと良い