react drag and drop list

Tony·2021년 9월 19일
0

react

목록 보기
24/82

지난번 순수 javascript만으로 animation이 있는 drag and drop list를 만들려다가 잘 되지 않았다.

  • javascript drag and drop 구현 시도와 시행착오

    javascript로 직접 구현하려 했으나 애니메이션발동 도중 DOM을 변경하거나
    (DOM 위치가 바뀌면 애니메이션이 바뀐 위치를 기준으로 동작하기 때문에 계산이 어렵다)
    애니메이션이 끝나기 전에 애니메이션의 도착지점을 변경하는 것이 어려워서 라이브러리를 사용하기로 했다

라이브러리를 사용하기로 결정했고 이번에 라이브러리를 사용해서 구현한 내용을 정리해보려한다.

라이브러리 비교 및 선정

  • sortablejs vs react-sortable-hoc vs react dnd

sortablejs

  • Weekly Downloads : 약 80만
  • 자바스크립트에서 사용하기 위해서 만들어진 라이브러리
  • sortablejs 예제
  • react-sortablejs를 사용하면 리액트에서도 편하게 사용가능
    • Weekly Downloads : 약 8만

react-sortable-hoc

react dnd

  • Weekly Downloads : 약 81만
  • drag and drop react 라이브러리 중 가장 많이 사용된다

선정 기준

  • inflearn 애니메이션과 가장 유사한 것
  • sortablejs가 거의 똑같고 나머진 mouseup 과 mousedown에서 애니메이션이 이동되는 방식이었다(drag api를 사용하지 않는 것으로 보임)

sortablejs로 결정

npm install --save react-sortablejs sortablejs
npm install --save-dev @types/sortablejs
// 사용 예 - 코드 1
const { createLectureData, lectureData, saveCourseInfoDone } = useSelector((state: RootState) => state.lecture);

const [whatYouCanLearn, setWhatYouCanLearn] = useState<ItemInterface[]>(
  lectureData?.courseInfo.whatYouCanLearn.map((item) => ({
  id: item.order,
  name: item.name,
  }))
);

<ReactSortable list={whatYouCanLearn} setList={setWhatYouCanLearn} animation={200} handle=".handle">
  {whatYouCanLearn.map((item, index) => (
    <TextListBox key={item.id} item={item} list={whatYouCanLearn} setList={setWhatYouCanLearn} index={index} />
  ))}
</ReactSortable>
// react-sortablejs에서 권장하는 item type interface - 코드 2
export interface ItemInterface {
    /** The unique id associated with your item. It's recommended this is the same as the key prop for your list item. */
    id: string | number;
    /** When true, the item is selected using MultiDrag */
    selected?: boolean;
    /** When true, the item is deemed "chosen", which basically just a mousedown event. */
    chosen?: boolean;
    /** When true, it will not be possible to pick this item up in the list. */
    filtered?: boolean;
    [property: string]: any;
}

// 내가 사용하는 item의 type - 코드 3
export type LectureInfoChild = {
  name: string;
  order: number | string;
};

// react-sortablejs에 맞게 변형 - 코드 4
useEffect(() => {
  setWhatYouCanLearn(
    lectureData?.courseInfo.whatYouCanLearn.map((item) => ({
    id: item.order,
    name: item.name,
    }))
  );
}, [lectureData?.courseInfo]);

key !== index

  • react-sortablejs 공식 문서에 key를 배열의 index로 사용하지 말라고 한다.

DO NOT use the index as a key for your list items. Sorting will not work.

In all the examples above, I used an object with an ID. You should do the same!

I may even enforce this into the design to eliminate errors.

고찰

  • 타입스크립트를 사용하면서 타입이 맞지 않으면 일부로 타입을 맞추려는 코드들이 있다.(코드 4같은 경우)
    타입을 맞추기 위한 이런 것이 잘 하고 있는 것인지 아닌지 스스로 판단하기 어려운 것 같다.

  • react-sortablejs에서 리스트 아이템의 전체가 아닌 특정 부분만 드래그를 가능하게 만들고 싶은 경우(핸들을 사용)
    코드 1에서 ReactSortable컴포넌트의 handle=".handle" 속성에서 클래스 이름을 지정 후
    아이템 컴포넌트의 핸들 부분에 클래스 이름을 맞춰주면 된다.

    <DynamicBox>
      <div>{item.name}</div>
      <div>
        <button onClick={onClickDelete} type="button">
          <DeleteIcon />
        </button>
        <DraggableButton className="handle"> // 핸들을 위한 클래스 이름 지정
          <DragHandleIcon />
        </DraggableButton>
      </div>
    </DynamicBox>
profile
움직이는 만큼 행복해진다

0개의 댓글