ユーザーアイコン

mizuko

約1か月前

0
0

dnd-kitを使ったリストの並び替えについて

Next.js
dnd-kit

気を付けるポイントとしては、

  • SortableItem用にidを定義する必要がある
  • touchActionのnoneを設定しないとモバイル操作がうまくいかない

以下実装例

<DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={handleDragEnd} modifiers={[ restrictToVerticalAxis, restrictToWindowEdges, restrictToParentElement, ]} > <SortableContext items={ideas.map((idea) => ({ id: idea.id }))} strategy={verticalListSortingStrategy} > <div className='mt-8 w-full grow rounded-3xl bg-gray-100 px-4 py-8 shadow-md'> <div className='item-center flex justify-center'> <div className='w-full'> <TextInput id='idea_title' type='text' variant='noneShadow' placeholder='アイデアを入力してください' maxLength={100} value={newIdeaTitle} onChange={(event) => { setNewIdeaTitle(event.target.value); }} /> </div> <div className='ml-4'> <button className='flex size-9 items-center justify-center rounded-full bg-gray-300 p-2 text-white shadow-md hover:bg-gray-500' onClick={handleAddIdea} > <PlusIcon /> </button> </div> </div> <ul className='mt-8'> {ideas.map((idea) => ( <SortableItem key={idea.sort} id={idea.id} ideaId={idea.ideaId} title={idea.title} handleCreateMemoButtonClick={handleCreateMemoButtonClick} handleDeleteIdea={handleDeleteIdea} /> ))} </ul> </div> </SortableContext> </DndContext> const SortableItem = ({ id, ideaId, title, handleCreateMemoButtonClick, handleDeleteIdea, }: SortableItemProps): JSX.Element => { const { attributes, listeners, setNodeRef, transform, transition, isDragging, } = useSortable({ id }); const style = { transform: CSS.Transform.toString(transform), transition, touchAction: 'none', }; return ( <> <li ref={setNodeRef} style={style} {...attributes} {...listeners} className={`my-2 flex items-center justify-between bg-white p-2 shadow ${isDragging ? 'cursor-grabbing' : 'cursor-grab'}`} > <span>{title}</span> <div className='ml-auto flex gap-4'> <CircleButton size='small' variant='tertiary' onClick={() => { handleCreateMemoButtonClick(title); }} > <PencilEditIcon className='size-4' /> </CircleButton> <CircleButton size='small' variant='gray' onClick={async () => { await handleDeleteIdea(ideaId); }} > <TrashIcon className='size-4' /> </CircleButton> </div> </li> </> ); };