react-beautiful-dnd는 3개의 요소로 이루어져있습니다.
- DragDropContext
- 드래그를 사용할 영역을 의미합니다
- contextAPI의 Provider같은 느낌입니다. (감싸주는 느낌..?)
- Droppable
- Drag해서 놓을 Drop할 영역입니다.
- Draggable을 감싸서 사용합니다.
- Draggable
- Drag 할 Item 입니다.
- 우리가 이용할 Item컴포넌트를 Draggable로 감싸주면 됩니다.
DragDropContext
DragDropContext는 3개의 prop이 있습니다.
- onDragStart
- Darg를 시작할 때 (Drag 할 Item을 클릭하고 움직이기 시작할 때) 호출
- onDragEnd
- Darg가 끝났을 때 (마우스를 땔때) 호출
- onDragUpdate
- Drag중에 발생하는 변화가 생겼을때 호출
Droppable
1. Droppable에는 droppabledId 라는 props가 있습니다.
해당 Id는 Context 안에서 유일해야합니다. (영역을 구분지어야 하기 때문)
Droppable에서 사용할 Draggable에 해당하는 자식 컴포넌트는 Element를 받는게 아닌
함수 형태로 받아야 합니다.
<Droppable droppableId={list.id}>
{(provided: any) => (
<div>
{items.map((item, i) => (
<Item key={item.id} item={item} index={i} />
))}
{provided.placeholder}
</div>
)}
</Droppable>
provided에는 droppable에 사용할 props가 모여있습니다.
1. data-rbd-droppable-context-id
2. data-rbd-droppable-id
직접 쓰면..
{(provided: any) => {
return (
<div
data-rbd-droppable-context-id={
provided.droppableProps["data-rbd-droppable-context-id"]
}
data-rbd-droppable-id={provided.droppableProps["data-rbd-droppable-id"]}
ref={provided.innerRef}
>
사실 이렇게 쓰고싶은사람은 없으니.
{(provided: any) => {
return (
<div {...provided.droppableProps} ref={provided.innerRef} >
스프레드를 씁시다.
2. 앗. ref도 지정해줘야합니다.
3. 마지막으로 placeholder 라는 프로퍼티가 있습니다.
droppable에 변화가 생긴다면 해당 부분을 처리해주는 역할을 합니다.
<Droppable droppableId={list.id}>
{(provided: any) => {
return (
<div {...provided.droppableProps} ref={provided.innerRef}>
<>
{items.map((item, i) => (
<Item key={item.id} item={item} index={i} />
))}
{provided.placeholder}
</>
</div>
);
}}
</Droppable>
Draggable
1. Draggable은 draggableId와 index가 필수입니다.
Item 컴포넌트를 Drag가 가능하게 하려면 Draggable로 감싸야합니다.
Droppable처럼 함수 형태로 작성해야합니다.
const Item = ({ item, index }) => {
<Draggable draggableId={item.id} index={index}>
{(provided: any) => {
return (
<div
{...provided.draggableProps}
{...provided.dragHandleProps}
ref={provided.innerRef}
>
{item.content}
</div>
);
}}
</Draggable>
}
draggableProps, dragHandleProps, 그리고 ref까지 작성 해줘야합니다.
draggableProps : Drag 가능한 요소에 적용되는 속성을 나타내며, 해당 요소의 이벤트 리스너 및 기타 속성을 정의할 수 있습니다.
(context에서 작성한 onDragStart , onDragEnd 같은 친구들..)
dragHandleProps : Drag 액션을 처리하는 드래그 핸들에 적용되는 속성을 나타내며, Drag가 발생하는 영역을 정의할 수 있습니다.
onDrag 함수들에 대해
{
draggableId: 'itemList',
type: 'TYPE'
reason: 'DROP',
source: {
droppableId: 'item1',
index:0,
},
destination: {
droppableId: 'item1',
index:1,
},
}
draggableId : Drag 한 객체의 id
source : Drag가 시작된 위치 Droppable의 Id와 시작할 때 item의 index
destination : Drag가 끝나는 위치 Droppable의 Id와 끝날때 Item의 index Droppable의 밖에 드래그 할 경우 null
source와 destination을 이용해야합니다.
const onDragEnd = (result: DropResult) => {
const { destination, source, draggableId } = result;
if (!destination) return;
if (destination.droppableId === source.droppableId && source.index === destination.index)
return;
const newItemIds = Array.from(column.itemIds);
//시작지점 source의 아이탬의 index를 잘라냅니다 (위치를 바꿔주기위해)
newItemIds.splice(source.index, 1);
//아이탬의 도착지 destination의 index 위치에 draggableId를 추가합니다 (잘라낸 아이탬의 id)
newItemIds.splice(destination.index, 0, draggableId);
//바뀐 newItemIds를 갱신
const newColumn = {
...column,
itemIds: newItemIds,
};
//갱신한 값을 Data를 가져와서 바꿔줍니다
const newData = {
...data,
columns: {
...data.columns,
[newColumn.id]: newColumn,
},
};
setData(newData);
}
다른 Droppable에도 이동하기
처음엔 어떻게 하는건지.. 어렵게 생각했었는데..
크게 다르지 않았습니다.
기존소스를 이용하면서 바뀐부분은 주석!
const onDragEnd = (result: DropResult) => {
const { destination, source, draggableId } = result;
if (!destination) return;
if (destination.droppableId === source.droppableId && source.index === destination.index)
return;
const sourceColumn = data.columns[source.droppableId]; // 출발지의 droppable정보
const destinationColumn = data.columns[destination.droppableId];// 도착지점의 droppable정보
if(source.droppableId === destination.droppableId){
//기존소스
/*column 을 sourceColumn 으로 변경
어짜피 시작과 끝이 같은 영역일 경우에만 동작하므로
source나 destination 아무거나 사용해도 괜찮습니다.
그 영역의 정보를 가지고 오는것이 중요
*/
const newItemIds = Array.from(sourceColumn.itemIds);
newItemIds.splice(source.index, 1);
newItemIds.splice(destination.index, 0, draggableId);
//...column 을 ...sourceColumn 으로 변경
const newColumn = {
...sourceColumn,
itemIds: newItemIds,
};
const newData = {
...data,
columns: {
...data.columns,
[newColumn.id]: newColumn,
},
};
setData(newData);
//여기까지 기존소스
}else{
//출발지와 도착지가 이제 다르기 때문에 따로 만들어줍니다.
const sourceItemIds = Array.from(sourceColumn.itemIds);
const destinationItemIds = Array.from(destinationColumn.itemIds);
sourceItemIds.splice(source.index, 1);
destinationItemIds.splice(destination.index, 0, draggableId);
const newSourceColumn = {
...sourceColumn,
itemIds: sourceItemIds,
};
const newDestinationColumn = {
...destinationItemIds,
itemIds: destinationItemIds,
};
const newData = {
...data,
columns: {
...data.columns,
[newSourceColumn.id]: newSourceColumn,
[newDestinationColumn.id]: newDestinationColumn,
},
};
setData(newData);
}
};
'React > React Library' 카테고리의 다른 글
[Redux] Redux Toolkit: 생산성을 높이는 리덕스 라이브러리 (0) | 2023.04.15 |
---|