0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

keitamaxAdvent Calendar 2024

Day 23

Reactでドラッグ&ドロップでListの並び替えをする

Last updated at Posted at 2024-12-22

はじめに

こんにちは、エンジニアのkeitaMaxです。

こちらのライブラリを使用して、ドラッグ&ドロップで並び替えできるリストを作成しようと思います。

Next.jsとTailwindCSSを使用しています。

インストール

以下をインストールします。

npm install @dnd-kit/core @dnd-kit/sortable

実装

ファイル構成は以下のようにしました。

/
└─ src/views
      └─ DragDropView
         ├─ index.ts
         ├─ index.stories.tsx
         └─ components/SortableItem
            └─ index.ts
DragDropView/index.tsx

import { DndContext, useSensor, useSensors } from '@dnd-kit/core'
import React, { useState } from 'react'
import { arrayMove, SortableContext, sortableKeyboardCoordinates, verticalListSortingStrategy } from '@dnd-kit/sortable'
import {
  closestCenter,
  KeyboardSensor,
  PointerSensor,
} from "@dnd-kit/core"
import { SortableItem } from './components/SortableItem'

export const DragDropView = React.memo(function DragDropView() {
  const [items, setItems] = useState(["Item 1", "Item 2", "Item 3", "Item 4"])

  const sensors = useSensors(
    useSensor(PointerSensor),
    useSensor(KeyboardSensor, {
      coordinateGetter: sortableKeyboardCoordinates,
    })
  )

  const handleDragEnd = (event: any) => {
    const { active, over } = event

    if (active.id !== over.id) {
      setItems((prevItems) => {
        const oldIndex = prevItems.indexOf(active.id)
        const newIndex = prevItems.indexOf(over.id)

        return arrayMove(prevItems, oldIndex, newIndex)
      })
    }
  }

  return (
    <DndContext
      sensors={sensors}
      collisionDetection={closestCenter}
      onDragEnd={handleDragEnd}
    >
      <SortableContext items={items} strategy={verticalListSortingStrategy}>
        <ul className="mx-auto max-w-md rounded bg-gray-100 p-4 shadow">
          {items.map((item) => (
            <SortableItem key={item} id={item} />
          ))}
        </ul>
      </SortableContext>
    </DndContext>
  )
})
export default DragDropView

DragDropView/index.stories.tsx
import { Meta, StoryObj } from '@storybook/react'
import { DragDropView } from '.'

const meta: Meta<typeof DragDropView> = {
  component: DragDropView,
  tags: ['autodocs'],
}
export default meta

type Story = StoryObj<typeof meta>

export const Default: Story = {}
SortableItem/index.tsx
import React from "react"
import { useSortable } from "@dnd-kit/sortable"
import { CSS } from "@dnd-kit/utilities"

interface SortableItemProps {
  id: string;
}

export const SortableItem: React.FC<SortableItemProps> = ({ id }) => {
  const { attributes, listeners, setNodeRef, transform, transition } =
    useSortable({ id })

  const style = {
    transform: CSS.Transform.toString(transform),
    transition,
  }

  return (
    <li
      ref={setNodeRef}
      style={style}
      {...attributes}
      {...listeners}
      className="mb-2 cursor-pointer rounded bg-white p-4 shadow hover:bg-gray-50"
    >
      {id}
    </li>
  )
}

これをnpm run storybookをして確認します。

挙動

draggablegif.gif

こんな感じでドラッグ&ドロップで動かせるようなリストが完成しました!

おわりに

この記事での質問や、間違っている、もっといい方法があるといったご意見などありましたらご指摘していただけると幸いです。

最後まで読んでいただきありがとうございました!

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?