Drag and Drop 구현하기

이지수·2023년 3월 1일
0

Drag and Drop 기능 추가하기

참조

HTML 드래그 앤 드롭 API - Web API | MDN

  • HTML 드래그 앤 드롭 API를 사용하여 원하는 목록을 드래그 가능하게 만든다
  • 사용자가 드래그 할 때 적절한 애니메이션을 준다
  • 사용자가 드래그를 멈췄는지 확인. 여기에도 애니메이션
  • 클라이언트가 목록을 재정렬 한 경우 항목의 위치릴 새 항목으로 업데이트

⇒ react-beautiful-dnd 사용하여 쉽게 구현

  1. 필요 모듈 설치하기

npm install react-beautiful-dnd --save

import {DragDropContext, Droppable, Draggable} from “react-beautiful-dnd”;

  • <DragDropConatext /> - wraps the part of your application you want to have drag and drop enabled for
  • <Droppable /> - An area that can be dropped into Contains
  • <Draggable /> - what can be dragged around
  1. api를 이용해 틀 만들기

    return (
        <div>
          <DragDropContext>
            <Droppable>
              {todoData.map((data) => (
                <Draggable>
                <div key={data.id}>
                  <div className="flex items-center justify-between w-full px-4 py-1 my-2 text-gray-600 bg-gray-100 border rounded">
                   <div className='items-center'>
                    <input
                      type="checkbox"
                      onChange={() => handleCompletedChange(data.id)}
                      defaultChecked={false}
                      />{" "}
                    <span className={data.completed ? "line-through" : undefined}>{data.title}</span>
                   </div>
                    <div className="items-center">
                      <button className='px-4 py-2 float-right' onClick={() => handleClick(data.id)}>x</button>
                    </div>
                  </div>
                </div>
                </Draggable>
              ))}
            </Droppable>
          </DragDropContext>
        </div>
      )
  • provided object에는 스타일 지정 및 조회를 위한 속성이 포함되어 있음
  • 사용자가 요소를 드래그하는 경우 className속성을 selected로 변경. 나중에 스타일 적용하는데 사용
  • placeholder속성은 목록에 빈 공간을 만듦. 드래그 작업을 자연스럽게 만든다

이슈

스크린샷 2023-03-01 오후 6.48.36.png

  • 리액트의 stricMode제거해주기
// index.js
root.render(
  ~~<React.StrictMode>~~
    <App />
  ~~</React.StrictMode>~~
);
  1. Dragging하는 요소의 스타일링 변경
<DragDropContext>
        <Droppable droppableId="todo">
          {(provided) => (
            <div {...provided.droppableProps} ref={provided.innerRef}>
          {todoData.map((data, index) => (
            <Draggable
              key={data.id}
              draggableId={data.id.toString()}
              index={index}
              >
                {(provided, snapshot)=>(
              <div
                key={data.id} {...provided.draggableProps} 
                ref={provided.innerRef} {...provided.dragHandleProps}
                className={`${snapshot.isDragging ? "bg-gray-400": "bg-gray-100"} flex items-center justify-between w-full px-4 py-1 my-2 text-gray-600 border rounded`}>
               
                  <div className='items-center'>
                    <input
                      type="checkbox"
                      onChange={() => handleCompletedChange(data.id)}
                      defaultChecked={false}
                    />{" "}
                    <span className={data.completed ? "line-through" : undefined}>{data.title}</span>
                  </div>
                  <div className="items-center">
                    <button className='px-4 py-2 float-right' onClick={() => handleClick(data.id)}>x</button>
                  </div>
                </div>
                )}
            </Draggable>
          ))}
          {provided.placeholder}
          </div>
          )}
        </Droppable>
      </DragDropContext>
  1. Dragging한 후 데이터 순서 적용(persistence)
const handleEnd = (result) => {
    if (!result.destination) return;

    const newTodoData = todoData;
    // 1. 변경시키는 아이템을 배열에서 지움
    // 2. return 값으로 지워진 아이템을 잡아줌
    const [reorderItem] = newTodoData.splice(result.source.index, 1);

    // 워나는 자리에 reorderItem을 insert해줍니다.
    newTodoData.splice(result.destination.index, 0, reorderItem);
    setTodoData(newTodoData);
  }

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

Array.prototype.splice() - JavaScript | MDN

리액트 불변성 지키기

불변성이란 사전적 의미로는 값이나 상태를 변경할 수 없는 것을 의미

자바스크립트 타입

  • 원시타입 : Boolean, String, Number, null, undefinded, Symbol (불변성)
  • 참조타입 : Object, Array (불변성 x)

원시타입에 대한 참조 및 값을 저장하기 위해 call stack 메모리 공간을 사용하지만 참조 타입의 경우 heap이라는 메모리 공간을 사용. 이 경우 call stack은 개체 및 배열 값이 아닌 메모리에만 heap 메모리 참조 Id를 값으로 저장

원시타입 → 고정된 크기로 call stack 메모리에 저장, 실제 데이터가 변수에 할당

참조타입 → 데이터 크기가 정해지지 않고 call stack 메모리에 저장, 데이터의 값이 heap에 저장되며 변수에 heap 메모리의 주소값이 할당

불변성 지키는 이유?

  1. 참조 타입에서 객체나 배열의 값이 변할 때 원본 데이터가 변경되기 때문에 이 원본 데이터를 참조하고 있는 다른 객체에서 예상치 못한 오류가 발생할 수 있어 프로그래밍의 복잡도가 올라감
  2. 리액트에서 화면을 업데이트할 때 불변성을 지켜서 값을 이전 값과 비교해서 변경된 사항을 확인한 후 업데이트하기 때문에 불변성을 지켜줘야함

불변성을 지키는 방법?

참조 타입에서는 값을 바꿨을 때 call stack 주소 값은 같은데 heap 메모리 값마 바꿔주기에 불변성을 유지할 수 없었으므로 아예 새로운 배열을 반환하는 메소드를 사용

spread operator, map, filter, slice, reduce

원본 데이터를 변경하는 메소드 ⇒ splice, push

profile
The only thing worse than starting something and failing...is not starting something

0개의 댓글