drag and drop 을 활용하여 sort 기능을 제공해주는 라이브러리
오늘은 react에서 drag and drop을 쉽게 활용할 수 있는 라이브러리를 소개해보려고 한다.
사실 react-beautiful-dnd를 사용하기 전엔 react-dnd를 사용했으나,
가 되었다.
버전 오류로 인한 해결은 아래 --legacy-peer-deps 라는 라이브러리를 같이 설치하면 해결이 된다.
(^18.2.0) 버전.
npm install --save react-beautiful-dnd --legacy-peer-deps
아래처럼 [ 임시의 정원, 황제, 대한제국, 통치 ] 와 같은 부모 List 가 있으며,
하위로 auidoList가 뿌려지게 되고, 이 오디오 리스트 또한 dnd 기능이 필요했다.
비교적 react-beautiful-dnd 라이브러리는 사용성이 간편한 편이라 큰 어려움은 없었다.
드래그 할 요소들을 감싸고 있는 wrapper 개념으로 drag 할 요소들의 가장 상위에서 사용해야 한다.
리스트 안에 리스트를 만들어야하기 때문에, 2개의 태그가 필요했다.
<DragDropContext>
...
<DragDrapContext>
...
</DragDrapContext>
...
</DragDropContext>
drop을 할 수 있는 영역을 감싸고 있다.
Droppable 함수 바로 하위로 오는 친구에게는
droppable로 사용할 컴포넌트에 적용이 되야하는 프로퍼티와
컴포넌트들이 서로 상호작용을 도와주는 ref 콜백의 역할을 적용시켜 주어야 한다.
ref={provided.innerRef}
{...provided.droppableProps}
<DragDropContext>
<Droppable>
<div
ref={provided.innerRef}
{...provided.droppableProps}
>
// 중제목 리스트
<DragDrapContext>
<Droppable>
// 중제목에 포함된 오디오 리스트
...
</Droppable>
</DragDrapContext>
</Droppable>
</DragDropContext>
drag를 할 수 있는 주체적인 요소이며, Draggable에는 세가지 요소가 필요하다.
또한 drappable 과 동일하게 하위로 떨어지는 태그에게도 역시
draggableProps 이라는 프로퍼티를 부여해주어야 하며,
dragHandleProps 이라는 실제로 drag가 어느 시점부터 handling 되는지,
적절한 컴포넌트에 부여해주면 된다.
(예를들어 왼쪽 = ham 모양의 버튼으로만 컨트롤 하고싶다면, 그 컴포넌트에 부여해줄 수 있다.)
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
<Draggable
index={index}
key={"subTopicList" + index}
draggableId={"subTopicList" + index}
>
{provided => (
<div
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
>
...
</div>
</Draggable>
drag를 마칠 때 일어나는 이벤트이다. DragDropContext 요소에 포함시켜주어야한다.
따로 함수를 빼서 다른곳에 다양하게 적용을 해두었다.
리스트들의 index 값들의 배치를 재 정렬해주는 함수이다.
export const setSequence = (list, startIndex, endIndex) => {
const result = Array.from(list);
const [removed] = result.splice(startIndex, 1);
result.splice(endIndex, 0 , removed);
return result;
}
Audio.jsx
subTopicList 및 상태들을 자식 components에게 넘겨줌
<ul className={styles.subList}>
{ data
? <SubTopicListDnd
subTopicList={subTopicList}
subTopicListDt={subTopicListDt}
setSubTopicList={setSubTopicList}
/>
: <p
className={"noData"}
style={{ paddingBottom: "3rem" }}
>
카테고리 / 전시관을 선택해주세요.
</p>
}
</ul>
SubTopicListDnd.jsx
가장 보여지는 중제목의 List
<DragDropContext onDragEnd={onDragEnd} >
<Droppable droppableId="subTopicList">
{(provided, snapshot) => (
<div
ref={provided.innerRef}
{...provided.droppableProps}
>
// 하위 List 생성
{subTopicList.map((data, index) => {
return (
<Draggable
index={index}
draggableId={"subTopicList" + index}
>
{provided => (
<div
key={data.id}
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
>
<SubTopicDetailDnd
data={data}
index={index}
subTopicList={subTopicList}
setSubTopicList={setSubTopicList}
/>
</div>
)}
</Draggable>
)
})}
{provided.placeholder}
</div>
)}
</Droppable>
</DragDropContext>
SubTopicDetailDnd.jsx
<DragDropContext onDragEnd={onDragEnd}>
<Droppable droppableId={"audioList"}>
{provided => (
<div
className={styles.listBox}
ref={provided.innerRef}
{...provided.droppableProps}
{...provided.dragHandleProps}
>
<li>
<div>
<h3
onClick={() => handleHide(index)}
>
{data.title} <KeyboardArrowDown/>
</h3>
</div>
<div
className={styles.contentRef}
ref={el => contentRef.current[index] = el}
>
{audioList.length === 1 ? (
... // dnd 기능 필요 x 목록
)
: audioList.length > 1 ? (
audioList.map((audio, i) => (
<Draggable
draggableId={"audioList" + i}
index={i}
>
{(provided, snapshot) => (
<div
key={audio.id}
ref={provided.innerRef}
{...provided.draggableProps}
style={getItemStyle(
snapshot.isDragging,
provided.draggableProps.style
)} >
<SubTopicAudioListDnd
provided={provided}
data={audio}
index={i}
handleOpenModal={handleOpenModal}
/>
</div>
)}
</Draggable>
)))
: (
<div className={styles.subAudioNoData}>
<p>오디오가 없습니다. 등록해주세요.</p>
<Button
onClick={() => handleOpenModal(data.id, null, true)}
style={{ background: "#a2b521" }}
>
등록
</Button>
</div>
)}
{audioList.length >= 1 &&
<Button
className={styles.addBtn}
onClick={() => handleOpenModal(data.id, null, true)}
style={{ background: "#a2b521" }}
>
추가
</Button>
}
</div>
</li>
{provided.placeholder}
</div>
)}
</Droppable>
</DragDropContext>
drag and drop 기능을 js에서는 sortable이라는 jquery 의 라이브러리 (?) 로
어렵지 않게 구현했던바가 있지만, react에서는 라이브러리를 제대로 숙지할 필요성이 있어
처음에는 곤란했따. 특히나 두 리스트를 컨트롤 한다는 부분에 있어서
적절한 예시를 찾지 못했기 때문에 !
내가 기억하고자,,, 마무리,,, 감사합니닷.