React/To-do 앱

React_to-do_5

oyatplum 2023. 1. 30. 20:33

5. To-do_1

: Drag and Drop 기능 추가하기

 

 

Drag and Drop 기능을 구현하는 순서로는

1. html 드래그 앤 드랍 api를 사용하여 원하는 목록을 드래그 가능하게 만든다.

2. 사용자가 드래그 할 때 적절한 애니메이션을 준다.

3. 사용자가 드래그를 멈췄는지 확인하고 여기에도 애니메이션을 준다.

4. 클라이언트가 목록을 재설정한 경우 항목의 위치를 새 항목으로 업데이트한다.

 

>> 이것을 쉽게 구현할 수 있도록 해주는 모듈이 react-beautiful-dnd 이다.

 

따라서 이 모듈을 설치해보자~!! 후후

 

 

요로콤시 해주면 된다.

 


 

 

여기서 제공해주는 드래그 앤 드랍 api를 살펴보면

1.  <DragDropContext /> : 드래그 앤 드랍 하길 원하는 부분 전체를 감싸준다. 2,3 포함

2. <Droppable /> : 드래그 앤 드랍하는 요소 전체를 감싸준다. 3포함

3. <Draggable /> : 드래그 앱 드랍하는 요소 하나를 감싸준다.

 

 

 

이제 투두 앱에서 위의 api들을 사용해 리스트 목록 하나를 드래그 앤 드랍할 것이다.

 

이렇게 우선 위의 내용과 투두 앱의 상황에 맞게 각각 넣어줬는데... 아직 여기서 끝난 것이 아니다!!!

 

더 추가해줘야 할 사항들이 남아있다.

 

 

 

먼저, 1. provided object 에는 스타일 지정 및 조회를 위한 속성이 포함되어 있다. 즉, provided 파라미터는 스타일링이나 어떠한 요소가 드래그 되고 있는지 찾는 것이다!

 

그리고 2. snapshot이라는 파라미터는 드래그를 하고 있는지 아닌지 등에 대한 정보를.. 지니는 것이다..!

 

사용자가 요소를 드래그 하는 경우, className 속성을 selected로 변경한다. 이는 나중에 스타일을 적용하는데 사용할 것이다.

 

3. placeholder 속성은 목록에서 빈 공간을 만들어, 드래그 작업이 자연스럽게 이루어지도록 해준당!!!

 

 

 

 

 

위의 사항들을 추가하여 List.js를 수정해보자!!!

 

 

... ?

전체 코드가 이렇다... 다..당황하지 말고 하나씩 살펴보자...

 

 

 


 

 

 

우선 Droppable부터 살펴보면....

 

 

이렇게 droppableId를 넣어준다. 내가 원하는 이름으로!

그리고 위에서 했던 provided도 추가해주고 div를 하나 새롭게 만들어줘야 한다.

div안에 droppable과 관련된 정보를 넣어줘야 하는 것이다.

 

먼저, provided 객체에는 droppableProps라는 프로퍼티가 있다.

이는 우리가 droppable로 사용할 컴포넌트에 적용되어야 하는 모든 props를 모아놓은 것으로 일일히 적용할 수도 있지만 ... 스프레드 연산자를 사용해서 간편하게 적용할 수 있다.

 

또한  innerRef라는 프로퍼티도 있다.

+) ref자체는 render메서드에서 생성된 dom노드나 react 엘리먼트에 접근하는 방법을 제공한다고 한다.

+) ref는 포커스, 텍스트의 선택 영역, 미디어의 재생, 애니메이션의 직접적인 실행 등에 사용된다.

 

 

 

 

 

그리고 Draggable 에선....

 

우선 map 메소드를 사용하니까 key 값을 목록의 유니크한 id 값으로 지정해줬다.

droppableId처럼 draggableId를 만들어줬다. 이는 해당 목록의 id에 접근해서 string으로 받기 위해 toString()을 이용했다.

(왜 string으로 받아야 하지..? 음.. 아무래도 위의 droppableId로 string인 "todo"로 받았으니까 이것도 string으로 해주는 것 같다..)

그리고 map의 인자로 index도 추가해줬다... 왜일까?!?!?!?!!??! 흠냐링...(뒤에 밝혀짐)

 

droppable과 마찬가지로 provided을 가져온다. 이때는 snapshot도!!

droppable처럼 또 작성을 해주는데.... 여기서는 dragHandleProps도 추가해줬다.

 

 

이렇게만 하면 드래그 앤 드랍을 할 때 약간 어색하게 스타일링이 되는 것을 확인할 수 있다.. 그래서 또 추가해준 것이

바로

 

placeholder!!! 그러면 확실히 자연스럽게 움직이는 것을 확인할 수 있다.

 

 

 

 

어 근데 드래그 앤 드랍 관련 구글링을 하다가 좋은 설명을 찾아냈다... 바로

 

 

1. DragDropContext

참고 링크의 Readme 파일을 보면 위 gif가 나와있는데, 각 컴포넌트의 역할을 정말 직관적으로 잘 와닿게 해준다.

  • DragDropContext는 onDragEnd라는 prop이 필수다. onDragEnd는 유저가 드래그를 했을 때 실행되는 함수다.
  • onDragEnd 함수를 통해서 드래그를 완료했을 때의 상태에 관한 argument를 받을 수 있다. 이를 활용하여 드래그 이후 원하는 상태로 화면을 바꾸는 등의 작업이 가능해진다.
  • DragDropContext는 children 요소가 필수다.

2. Droppable

말 그대로 Droppable, 즉, Drag 했을 때 Drop 할 수 있는 구역을 말한다.

  • droppableId 라는 prop에 id를 필수로 만들어줘야한다.
  • Droppable은 children이 필수다. 특이하게도 이 children은 반드시 함수여야만 한다.
  • 이 함수는 자동으로 provided 라는 이름으로 주로 불리는 argument를 갖는데, 이것의 주요 속성은 다음과 같다.
    1) innerRef
    2) placeholder: Droppable 내부의 요소를 드래그 했을 때, Droppable의 사이즈를 유지시켜준다.
    3) droppableProps: 드래그 했을 때 옮길 수 있는 부분에 사용된다.

3. Draggable

말 그대로 Drag할 요소를 말한다.

  • Droppable과 마찬가지로, draggableId라는 id를 나타내는 prop이 필수다.
  • Draggable 역시 children이 필수다. 그리고 이 childre은 반드시 함수여야 한다.
  • 이 함수 또한 provided라고 불리는 argument를 자동으로 갖는데 주요 속성은 Droppable과는 조금 다르다.
    1) innerRef
    2) draggableProps : 드래그시 옮겨지는 부분에 사용된다.
    3) dragHandleProps : 드래그를 하기 위해 마우스가 눌러야하는 부분에
    사용된다.

 

출처 : https://velog.io/@stakbucks/Reactbeautifuldnd

 

React-beautiful-dnd

React-beautiful-dnd로 웹 Drag and Drop 구현하기.

velog.io

 

 

내가 위에 조잘거린 것보다 훨씬 이해하기 쉽다!! 헤헷...

 

 


 

 

위에처럼 구현하면 드래그 앤 드랍은 이루어지지만 결정적으로 목록들의 순서가 바뀌지 않는다.

 

그래서 또 작업을 해줘야 함... 아오

 

1. Dragging 하는 요소의 스타일링을 변경해보자!!

이때는 snapshot을 이용하면 된다.

위에서처럼 snapshot은 드래그를 하고 있는지 아닌지 등에 대한 정보를 지니는 것이니까!!

 

 

 

 

이 코드를 보면.. className에서 다이나믹하게.. 구현을 했다.

흠흠 snapshot이 dragging인 경우에는 조금 더 진한 색으로 해줬다. 

 

그런데 위의 key가 있는 div와 className이 있는 div로 나눠져 있어서 이걸 하나로 합쳐보자

 

 

이렇게!! ㅎㅎ

 

 

 

그러면

 

이렇게 드래그 하는 목록은 진한 회색이 된다.

 

 

 

 

2. 그리고 Dragging한 후 데이터의 순서를 적용해보자!!

 

 

 

이렇게 DragDropContext 안에 onDragEnd 즉, 드래그가 끝났을 때 handleEnd 함수가 호출되도록 했다.

 

 

 

그리고 handleEnd 함수에 result를 받아서 result에 무엇이 오는지 콘솔로 찍어보면

 

이렇게 찍힌다... 여기서 아까 왜 draggable에 index인자를 추가해줬는지 알 수 있다.

첫 번째 목록에서 두 번째 목록으로 순서를 옮기려고 하면 저렇게 index의 destination이 1이고 source가 0인 것을 확인할 수 있다.

 

따라서 이 destinationsource를 이용해서 순서를 변경할 것이다.

 

 

 

어떻게 하냐면...

 

 

이렇게.... ㅎ

우선 destination이 없을 경우엔 그냥 return!

 

자... 그리고 드래그 하기 전 기존 목록들의 배열인 todoData를 newTodoData로 일단 받아놓고!!

splice 메소드를 사용한다.

 

splice 메소드는 배열의 기존 요소를 삭제 또는 교체하거나 추가하여 배열의 내용을 변경한다.

 

그래서 이 splice를 이용해 우선 드래그하려고 잡은 그 목록(result.source.index)을 배열에서 삭제한다. 여기서 1은 한 개를 삭제한다는 뜻!

삭제한 배열을 새로운 reorderedItem이라고 한다.

 

이제 삭제한 그 목록을 reorderedItem 배열에 추가해준다. 역시나 splice를 사용해서 reorderedItem에 드랍한 장소(result.destination.index)를 추가하는 것이다!!

 

마지막으로 이렇게 새롭게 만든 newTodoData를 setTodoData인 setter를 통해 todoData의 state를 변경해주면 끝이다!!

 

 

 

 

헤헤ㅔ.. 그럼 목록이 순서가 잘 바뀐다.....

 

 

하 정말 길었다 정말......

 

 

 


 

+) 추가적으로 고생한 부분

 

 

 

처음에 코드를 아무리 짜도 드래그가 먹히질 않았다...

 

 

 

 

 

이렇게 에러만 나올 뿐...

 

 

그 이유는

 

 

index.js에서 render 부분에 있는 StrictMode 때문이라고 한다!!! 

 

 

그래서

 

이렇게  StrictMode를 지워줬더니 핑핑 잘만 돌아가더라....ㅋㅋ.... 흐어 고생하다가 결국 에러 해결하니까 너무 상쾌하도라.......

아무튼 이렇게 해서 드래그 앤 드랍 기능 구현까지 완성!!

 

 

 

 

 

 

'React > To-do 앱' 카테고리의 다른 글

React_to-do_7  (1) 2023.02.01
React_to-do_6  (0) 2023.01.31
React_to-do_4  (1) 2023.01.29
React_to-do_3  (1) 2023.01.28
React_to-do_2  (0) 2023.01.27