
드래그 앤 드롭(Drag & Drop) 기능을 구현하기 위해 다양한 라이브러리와 방법을 비교한 결과, dnd-kit이 가장 적합하다고 판단하여 선택하게 되었습니다.
dnd-kit은 최신 React 패턴(예: Hooks)을 적극적으로 활용하여 선언적이고 직관적인 방식으로 드래그 앤 드롭을 구현할 수 있습니다.useState, useEffect 등)와 자연스럽게 통합됩니다.draggable 요소와 droppable 영역을 자유롭게 구성할 수 있으며, 애니메이션 효과, 드래그 시작/종료 시의 이벤트 핸들링까지 유연하게 커스터마이징할 수 있습니다.dnd-kit은 불필요한 렌더링을 줄이고 최소한의 코드 크기로 동작하도록 설계되었습니다.To-Do List 같은 애플리케이션에서도 부드러운 UX를 유지할 수 있습니다.dnd-kit은 현재 활발하게 유지보수되고 있으며, 공식 문서와 커뮤니티 자료가 많아 문제 발생 시 쉽게 해결할 수 있습니다.| 라이브러리 | 장점 | 단점 | 비교 결과 |
|---|---|---|---|
| dnd-kit (선택) | 1. React Hook 기반 API 사용 2. 높은 커스터마이징 지원 3. 경량화 및 최적화 | 1. 일부 고급 기능(예: 리스트 내부에서 드래그 종료 후 정렬 유지)은 추가 구현 필요 | ✅ 유연하고 모던한 기능 제공 |
| react-beautiful-dnd | 1. 간단한 리스트 재정렬 구현이 용이 | 1. 유지보수 중단 (React 최신 버전과의 호환성 문제 발생) 2. 커스터마이징 제한 | ❌ 최신 React와 호환되지 않아 비효율적 |
| React DnD | 1. 강력한 기능 지원 (다양한 드래그 & 드롭 시나리오 구현 가능) | 1. API가 복잡하고 학습 곡선이 높음 2. 간단한 To-Do List 재정렬에는 과한 기능 | ❌ 학습 난이도가 높고 불필요한 기능이 많음 |
| 커스텀 솔루션 (IntersectionObserver 활용) | 1. 외부 라이브러리 의존성이 없음 | 1. 직접 구현 시 많은 시간과 리소스 필요 2. 복잡한 기능을 완벽하게 구현하기 어려움 | ❌ 유지보수 부담이 크고 비효율적 |
react-beautiful-dnd는 유지보수가 중단되었고, React DnD는 API가 너무 복잡하며, 직접 커스텀 구현은 시간이 오래 걸리는 단점이 있습니다.dnd-kit은 최신 React와 좋은 호환성을 갖으며, 성능 최적화와 확장성을 동시에 제공하기 때문에 Coworkers 프로젝트에서 가장 적합한 선택이라고 생각했습니다.💡 dnd-kit을 활용하여 팀 페이지 To-Do List에서 할 일 목록을 드래그 & 드롭으로 정렬하는 과정을 구현하였습니다.
useSensor와 useSensors를 사용하여 마우스 & 터치 이벤트 모두 지원closestCenter 전략을 사용하여 최적의 UX 제공useState)하고, 변경 즉시 서버에 업데이트const sensors = useSensors(
useSensor(PointerSensor, {
activationConstraint: { distance: 10 },
}),
);
const handleDragStart = (event: DragStartEvent) => {
const { active } = event;
setActiveId(active.id as number);
};
const handleDragEnd = (event: DragEndEvent) => {
const { active, over } = event;
if (!over || active.id === over.id) {
setActiveId(null);
return;
}
const oldIndex = items.findIndex((item) => item.id === active.id);
const newIndex = items.findIndex((item) => item.id === over.id);
if (oldIndex !== -1 && newIndex !== -1) {
const newItems = arrayMove(items, oldIndex, newIndex);
setItems(newItems);
editTaskListOrder({
groupId,
id: Number(active.id),
displayIndex: newIndex,
});
queryClient.setQueryData<GroupResponse>(
['group', groupId],
(oldData?: GroupResponse): GroupResponse | undefined => {
if (!oldData) return oldData;
return {
...oldData,
taskLists: newItems,
};
},
);
}
setActiveId(null);
};
return(
<DndContext
collisionDetection={closestCenter} // 가장 가까운 요소를 감지하여 올바른 위치로 드롭
sensors={sensors} // 마우스 및 터치 이벤트 감지
onDragStart={handleDragStart} // 드래그 시작 시 실행
onDragEnd={handleDragEnd} // 드래그 종료 후 실행
>
{/* SortableContext: 리스트 아이템을 정렬 가능한 컨텍스트로 설정 */}
<SortableContext items={items} strategy={verticalListSortingStrategy}>
{/* 할 일 목록을 렌더링하는 컨테이너 */}
<div className="할 일 목록을 표시하는 컨테이너 (스크롤 적용 가능)">
</div>
</SortableContext>
{/* DragOverlay: 드래그 중인 아이템을 오버레이 형태로 표시 */}
<DragOverlay>
{/* 드래그 중인 아이템을 별도로 렌더링하여 UI 일관성 유지 */}
</DragOverlay>
</DndContext>
);
팀 프로젝트에서 dnd-kit을 활용하여 할 일 목록(TodoList)의 Drag & Drop 기능을 구현하던 중 모바일 환경(특히 iOS)에서 드래그가 정상적으로 동작하지 않는 문제를 발견했습니다.
이를 해결하기 위해 다양한 접근 방식을 시도했고, 최종적으로 스타일 수정과 센서(sensor) 최적화를 통해 문제를 해결하였습니다.
이 글에서는 발생한 문제, 원인 분석, 해결 과정을 정리하겠습니다.
iOS Safari를 포함한 일부 모바일 브라우저는 터치 기반 UI에서 기본 동작(예: 텍스트 선택, 컨텍스트 메뉴, 링크 클릭 등)을 제공하기 때문에,
이를 적절히 제어하지 않으면 드래그 이벤트보다 기본 이벤트가 우선 실행될 수 있습니다.
CSS 스타일을 수정하여 터치 이벤트의 기본 동작을 차단하면 정상적인 드래그 기능을 구현할 수 있습니다.
WebkitUserSelect: 'none', // 텍스트 선택 방지 (iOS 및 WebKit 기반 브라우저)
WebkitTouchCallout: 'none', // iOS Safari에서 기본 컨텍스트 메뉴(복사, 저장 등) 비활성화
iOS 기본 컨텍스트 메뉴 차단 - Webkit 설정 추가
이제 iOS에서도 기본 컨텍스트 메뉴가 뜨지 않고, 올바르게 Drag & Drop이 작동합니다.
기존에 사용하던 PointerSensor는 마우스, 터치, 펜 입력을 모두 감지하는 장점이 있지만,
모바일에서는 터치 이벤트를 세밀하게 제어하기 어렵고, 의도치 않은 드래그가 발생할 가능성이 높았습니다.
const sensors = useSensors(
useSensor(PointerSensor, {
activationConstraint: { distance: 10 }, // 10px 이상 이동해야 드래그 시작
}),
);
터치 입력 개선 - MouseSensor + TouchSensor 적용
const sensors = useSensors(
useSensor(MouseSensor, {
activationConstraint: {
distance: 10, // 10px 이상 이동해야 드래그 시작
},
}),
useSensor(TouchSensor, {
activationConstraint: {
delay: 150, // 150ms 이상 터치 후 드래그 시작 (짧은 터치는 클릭으로 처리)
tolerance: 5, // 5px 이하의 미세한 움직임은 드래그로 인식하지 않음
},
}),
);
✅ 의도치 않은 드래그 방지 → 터치가 길게 유지되었을 때만 드래그가 활성화됨
✅ 모바일 터치 감도 개선 → 손가락이 가볍게 움직이는 정도로는 드래그가 발생하지 않음
✅ 스크롤 방해 최소화 → 화면을 스크롤할 때는 드래그가 실행되지 않도록 설정
| 수정 전 | 수정 후 |
|---|---|
![]() | ![]() |
이번 개선을 통해 dnd-kit을 활용한 드래그 앤 드롭 기능이 iOS 모바일 환경에서도 정상 동작하도록 최적화할 수 있었습니다.
1️⃣ iOS에서 기본 터치 이벤트 차단 → WebkitUserSelect: 'none', WebkitTouchCallout: 'none' 설정
2️⃣ 센서 최적화 → PointerSensor 대신 MouseSensor + TouchSensor로 세밀한 입력 감지
3️⃣ 터치 감도 조정 → delay와 tolerance를 조절하여 모바일에서 자연스러운 UX 구현
이 과정을 통해 PC와 모바일 환경 모두에서 안정적으로 드래그 앤 드롭이 가능해졌습니다.