1. Draggable 이란?
React-Draggable은 드래그로 아이템의 순서를 변경하기보다,
컴포넌트를 드래그해서 위치를 옮기는 기능에 강점이 있는 라이브러리입니다.
2. React-Beautiful-DnD, React DnD랑의 차이점은?
일단 사용량 자체만 보자면
내가 사용한 React-Draggable이 사용량이 훨씬 많다.
React-Draggable과 React-Beautiful-DnD, React-DnD의 차이점은
React-DnD, Beautiful-DnD :
아까 언급했듯이 Draggable은 요소보단 컴포넌트에 중점이라면, React-DnD와 Beautiful-DnD는 요소가 중점이라고 생각하면 된다.
드래그로 아이템의 순서를 변경할때 편하며, 둘의 차이점을 보자면 React-DnD는 UI/UX가 미리 정해져있지 않은 경우가 있지만
Beautiful-DnD는 좋은 UI/UX나 동작이 이미 정의가 되어있다.
그래서 사용량으로 총합해서 보자면 Draggable > Beautiful-DnD > React-DnD 순으로 많이 쓰인다.
나도 그래서 처음엔 당연히 사용량이 많은 Draggable이 좋겠지 하고 선택을 했다.
3. 설치 및 사용법
1. 라이브러리 설치
npm install react-draggable
2. 사용하고자 하는 컴포넌트에 선언
import Draggable from "react-draggable";
3. 드래그하고자 하는 컴포넌트를 감싸주기
<Draggable>
<div>
Can Drag
</div>
</Draggable>
4. 실제 사용해보기
일단 스포츠 경기장에 드래그 가능한 요소를 추가해야하기 때문에
요소들에 Draggable을 넣어준다.
{BasketplayersList.map((player) => (
<div key={player.id} style={{position: "absolute"}}>
<div style={{position: "relative"}}>
<Draggable
defaultPosition={{ x: player.x, y: player.y }}
bounds={bounds}
>
<D.PlayerContainer style={{cursor: "pointer"}}>
<People/>
<D.PlayerText style={{ userSelect: 'none' }}>
{player.name}
</D.PlayerText>
</D.PlayerContainer>
</Draggable>
</div>
</div>
))}
하지만 이렇게 한다면, 요소안에서만 움직이지 않을 수 있다.
그렇기 때문에 미리 따온 이미지에 useRef를 사용해서 요소의 크기만큼 움직일 수 있게끔 해준다.
const formationFieldRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (formationFieldRef.current) {
const { left, top, right, bottom } = formationFieldRef.current.getBoundingClientRect();
setBounds({ left, top, right: right - left - 70, bottom: bottom - top - 70 }); //right, bottom에 요소크기 빼기
}
}, []);
<D.ImgBox ref={formationFieldRef} img = {BasketField} style={{position: "relative"}}>
크기가 측정된 이미지의 크기를 바탕으로 bounds를 설정해, 요소들의 움직임을 제한한다.
여기서 가끔 이미지의 크기만큼 움직이긴 하는데 이미지에 접근을 못하는 문제가 생겼는데,
이러한 문제는 relative, absolute를 주며 해결하였고,
또 다른 문제가 생겼는데 바로 defaultPosition을 요소별로 같게 줘도 서로의 좌표가 다르게 나온다는 것이다.
예를 들어 0 ,0으로 defaultPosition을 줬을때 요소들이 멀어지고, 각자의 0, 0좌표가 모두 다르게 나온다.
그런 문제도 처음에 겹치지 않아서 문제인 것이니 relative, absolute를 줘서 해결하였다.
<div key={player.id} style={{position: "absolute"}}>
<div style={{position: "relative"}}>
<Draggable
defaultPosition={{ x: player.x, y: player.y }}
bounds={bounds}
nodeRef={formationFieldRef}
>
<D.PlayerContainer style={{cursor: "pointer"}}>
<People/>
<D.PlayerText style={{ userSelect: 'none' }}>
{player.name}
</D.PlayerText>
</D.PlayerContainer>
</Draggable>
</div>
</div>
5. 마무리
처음 사용해보는 라이브러리라 찾아보는 자료들도 많고, 생각했던 것보다 많이 걸렸던 것 같지만
만드는 것 자체가 재밌어서 질리지가 않았다.