📌 설치 및 임포트
npm install @dnd-kit/core @dnd-kit/sortable @dnd-kit/utilities
import {
DndContext, useSensor, useSensors,
MouseSensor, TouchSensor, closestCenter
} from "@dnd-kit/core";
import {
SortableContext, useSortable,
arrayMove, verticalListSortingStrategy
} from "@dnd-kit/sortable";
import { CSS } from "@dnd-kit/utilities";
📌 컨텍스트 감싸기
const sensors = useSensors(
useSensor(MouseSensor, { activationConstraint: { distance: 5 } }),
useSensor(TouchSensor, { activationConstraint: { delay: 150, tolerance: 5 } })
);
<DndContextsensors={sensors}
collisionDetection={closestCenter}
onDragEnd={handleDragEnd}
>
<SortableContextitems={data.map(i => i.나의Id값으로지정할값 )}
strategy={verticalListSortingStrategy}
>
{data.map(item => (
<SortableItem key={item.나의Id값으로지정할값} id={item.나의Id값으로지정할값}>
{/* 내용 */}
</SortableItem>
))}
</SortableContext>
</DndContext>
📌 SortableItem 구현
function SortableItem({ id, children }) {
const {
attributes, listeners,
setNodeRef, transform,
transition, isDragging
} = useSortable({ id });
const style = {
transform: CSS.Transform.toString(transform),
transition,
cursor: isDragging ? "grabbing" : undefined
};
return (
<li ref={setNodeRef} style={style} {...attributes} {...listeners}>
{children}
</li>
);
}
function handleDragEnd({ active, over }) {
if (!over) return;
const oldIndex = userGroupChildren.findIndex(
item => item.나의Id값으로지정할값 === active.id
);
const newIndex = userGroupChildren.findIndex(
item => item.나의Id값으로지정할값 === over.id
);
setUserGroupChildren(
arrayMove(userGroupChildren, oldIndex, newIndex)
);
}
🌟 실수 1: items prop 불일치
SortableContext의 items에 실제 id 배열을 넘기지 않아 transform이 계속 undefined 발생items={data.map(i => i.나의Id값으로지정할값)}
로 명확히 id 값만 공유
🌟 실수 2: handleDragEnd에서 id 미공유
active.id, over.id가 나의Id값으로지정할값과 매칭되지 않음 → findIndex 실패useSortable({ id: item.나의Id값으로지정할값 }) 과findIndex(item => item.나의Id값으로지정할값 === active.id)SortableContext에 넘기는 items 와 useSortable({ id }) id 값이 100% 일치하는지console.log(transform) 이전에 Context와 id 배열이 제대로 세팅됐는지 체크forwardRef 적용하기