완성본
드래그할 수 있는 요소로 변경 — draggable={true}
드래그 시작 — onDragStart 이벤트 트리거
state.draggedFrom
state.isDragging
state.originalOrder
마우스 커서가 드롭 가능한 영역에 있을 때 — onDragOver 이벤트 트리거
drop 이벤트를 사용할 수 있도록 dragOver 기본 이벤트 방지 — e.preventDefault()
마우스 포인터 위치에 있는 요소의 인덱스 저장 — state.draggedTo
엘리먼트 순서 변경 — state.updatedOrder
드래그중인 아이템을 마우스 포인터 위치(draggedTo 인덱스)로 이동. 기존 마우스 포인터 위치에 있던 요소는 바로 뒤로 밀림.
드롭 가능한 영역에서 드롭했을 때 — onDrop 이벤트 트리거
HTML 드래그앤드롭 Web API를 이용해 리스트 엘리먼트의 순서를 마우스 드래그앤드롭으로 바꿀 수 있다. 엘리먼트의 draggable
속성을 true
로 주면 해당 요소는 드래그 가능한 객체가 된다. 이미지, 링크, 선택한 텍스트(텍스트 블록)는 기본적으로 드래그할 수 있다. 드래그 가능 상태가 되면 onDragStart
같은 드래그 관련 이벤트를 사용할 수 있다. onDragStart
는 드래그가 시작되면 트리거되는 이벤트다.
// 리스트 요소
<div draggable="true" onDragStart={startDragging}>
Drag Me 🍰
</div>
엘리먼트에 onDrop
과 onDragOver
이벤트를 걸면 드롭 가능한 영역(유효한 드롭 대상)이 된다. 이 두 이벤트를 활용해 드래그앤드롭 기능을 구현할 수 있다. onDragOver
는 마우스 포인터에 있는 요소가 유효한 드롭 대상일 때 트리거 되며, onDrop
은 드롭 가능한 영역에서 드롭했을 때 트리거되는 이벤트다.
<section onDrop={updateDragAndDropState} onDragOver={receiveDraggedElements}>
Drop here 🤲🏻
</section>
드래그한 (요소)데이터와 상호 작용하기 위해 setData()
와 getData()
같은 이벤트 메서드를 사용할 수도 있다. 현재 드래그 하고 있는 요소 정보(id 등)를 setData()
를 통해 저장하고, 드롭했을 때 getData()
를 통해 요소 정보를 불러온 후 재정렬 하는 방식으로 활용할 수 있다.
event.dataTransfer.setData(key, value) // 여러 key를 이용해 다수의 데이터를 저장할 수 있다
event.dataTransfer.getData(key)
리액트 컴포넌트 바깥 영역에 리스트를 렌더할 상태(items)와, 드래그앤드롭과 관련한 상태의 초기값을 정의한다. 드래그앤드롭 상태엔 드래그 중인 요소의 인덱스, 업데이트 전후의 렌더 리스트(items), 드래그 상태를 저장하는 곳이다.
const items = [
{ number: '3', title: '👨🏻💻 Tech Man' },
// 생략
];
const initialDnDState = {
draggedFrom: null, // 드래그를 시작한 요소의(마우스를 클릭하여 움직인 요소) 인덱스
draggedTo: null, // 드롭 대상 요소의 인덱스(드래그하여 마우스 커서가 위치한 요소의 인덱스)
isDragging: false, // 드래그 여부 Boolean
originalOrder: [], // 드롭하기전(순서가 바뀌기 전) 기존 list
updatedOrder: [], // 드롭한 후 순서가 바뀐 list
};