[React] Drag and Drop 사용 방법

react-beautiful-dnd을 사용하여 React에서 깔끔하고 사용하기 쉬운 드래그, 드롭, 애니메이션을 적용하는 방법에 대해 알아보겠습니다.

설치

1
$ npm i react-beautiful-dnd

TypeScript 사용 시 추가로 설치합니다.

1
$ npm i --save-dev @types/react-beautiful-dnd

사용

임시 데이터 **[‘a’, ‘b’, ‘c’, ‘d’, ‘e’, ‘f’]**를 사용하여 카드 형태의 드래그, 드롭을 구현해 봤습니다.

1
2
3
4
5
6
7
// atoms.tsx
import { atom } from 'recoil';

export const toDoState = atom({
key: 'toDo',
default: ['a', 'b', 'c', 'd', 'e', 'f'],
});

DragDropContext, Draggable, Droppable 를 사용하여 구성합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
// App.tsx
import { DragDropContext, Draggable, Droppable, DropResult } from 'react-beautiful-dnd';
import { useRecoilState } from 'recoil';
import styled from 'styled-components';
import { toDoState } from './atoms';

const Wrapper = styled.div`
display: flex;
max-width: 480px;
width: 100%;
margin: 0 auto;
justify-content: center;
align-items: center;
height: 100vh;
`;

const Boards = styled.div`
display: grid;
width: 100%;
grid-template-columns: repeat(3, 1fr);
`;

const Board = styled.div`
padding: 20px 10px;
padding-top: 30px;
background-color: gray;
border-radius: 5px;
min-height: 200px;
`;

const Card = styled.div`
border-radius: 5px;
margin-bottom: 5px;
padding: 10px 10px;
background-color: white;
`;

function App() {
const [toDos, setToDos] = useRecoilState(toDoState);
const onDragEnd = ({ draggableId, destination, source }: DropResult) => {
if (!destination) return;

setToDos((oldToDos) => {
const copyToDos = [...oldToDos];
// 1) Delete item on source.index
copyToDos.splice(source.index, 1);
// 2) Put back the item on the destination.index
copyToDos.splice(destination?.index, 0, draggableId);
return copyToDos;
});
};

return (
<DragDropContext onDragEnd={onDragEnd}>
<Wrapper>
<Boards>
<Droppable droppableId="one">
{(provided) => (
<Board ref={provided.innerRef} {...provided.droppableProps}>
{toDos.map((toDo, index) => (
<Draggable key={toDo} draggableId={toDo} index={index}>
{(provided) => (
<Card ref={provided.innerRef} {...provided.dragHandleProps} {...provided.draggableProps}>
{toDo}
</Card>
)}
</Draggable>
))}
{provided.placeholder}
</Board>
)}
</Droppable>
</Boards>
</Wrapper>
</DragDropContext>
);
}

export default App;

DraggabledraggableProps는 모든 영역을 dragHandleProps는 특정 영역을 통해서만 드래그할 수 있도록 설정할 수 있습니다.

Draggable list를 렌더링 하는 경우 각 Draggable에 key prop을 추가하는 것이 중요합니다. key는 list 내에서 고유해야 합니다. key에 item의 index가 포함되어서는 안 되기 때문에 일반적으로 draggableId를 key로 사용합니다.

참고

Share