react-beautiful-dnd

Yeom Jae Seon·2021년 2월 9일
14

개발일지

목록 보기
7/8
post-thumbnail

react-beautiful-dnd 사용하게 된 계기

  • side project로 진행하는 todolist들을 drag and drop으로 카드를 재구성할수 있게 하고싶었다.
  • react-dnd, 커스텀하게 직접 dnd를 구현.. 등등 여러방면으로 고민을하면서 codesandbox에서 실습을했는데 너무 어렵고 복잡했다.. 특히 react-dnd..
  • 비교적 간단히 dnd를 구현할수있는 react-beautiful-dnd라이브러리 사용하기로 결정
  • 다음에 혹시나 사용할때를 위해 메모.

그럼 시작해보자.

DragDropContext

react-beautiful-dnd를 적용하고 싶은 곳에 Wrapper컴포넌트로 DragDropContext를 사용한다.
import {DragDropContext} from 'react-beautiful-dnd'
우선 임포트 하고하자.

import "./styles.css";
import React from "react";
import { DragDropContext } from "react-beautiful-dnd";

const todos = [
  { id: "1", title: "공부" },
  { id: "2", title: "헬스" },
  { id: "3", title: "독서" },
  { id: "4", title: "산책" },
  { id: "5", title: "요리" }
];

export default function App() {
  return (
    <DragDropContext>
      <ul>
        {todos.map(({ id, title }) => (
          <li key={id}>{title}</li>
        ))}
      </ul>
    </DragDropContext>
  );
}

이렇게 우선 dnd를 적용하고싶은 곳에 래핑한다.

Droppable로 드랍가능하게 만들기

import { DragDropContext, Droppable } from "react-beautiful-dnd";
임포트하고

    <DragDropContext>
      <Droppable droppableId="todos">
        {(provided) => (
          <ul className="todos">
            {todos.map(({ id, title }) => (
              <li key={id}>{title}</li>
            ))}
          </ul>
        )}
      </Droppable>
    </DragDropContext>

DragDropContext로 래핑한 컴포넌트 내부에 Drop을 적용하고 싶은 리액트 엘리먼트를 감싼다. 이때 droppableId를 설정해줘서 drop할 엘리먼트를 추적가능하게한다.

          <ul
            className="todos"
            {...provided.droppableProps}
            ref={provided.innerRef}
          >
            {todos.map(({ id, title }) => (
              <li key={id}>{title}</li>
            ))}
          </ul>

추가로 props들을 추가해준다.

Draggable로 드래그 가능하게 하기

import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd";
임포트하고

          <ul
            className="todos"
            {...provided.droppableProps}
            ref={provided.innerRef}
          >
            {todos.map(({ id, title }) => (
              <Draggable key={id}>{(provided) => <li>{title}</li>}</Draggable>
            ))}
          </ul>

드래그가능하게 하고싶은 리액트 엘리먼트를 래핑한다. 나는 li태그 엘리먼트 부분을 드래그하고싶음.

            {todos.map(({ id, title }, index) => (
              <Draggable key={id} draggableId={id} index={index}>
                {(provided) => <li>{title}</li>}
              </Draggable>
            ))}

그리고 리스트의 인덱스를 받아서 Draggable 속성들을 추가해준다.
Draggable도 Droppable처럼 draggableId로 고유한 id가필요하다

              <Draggable key={id} draggableId={id} index={index}>
                {(provided) => (
                  <li
                    ref={provided.innerRef}
                    {...provided.dragHandleProps}
                    {...provided.draggableProps}
                  >
                    {title}
                  </li>
                )}
              </Draggable>

마지막으로 몇가지 속성을 추가해준다.

이젠 드래그 드랍이 가능하다.

근데 워닝이 아직도 뜨기때문에
Droppable로 래핑한 맨마지막 JSX에 {provided.placeholder}이 구문을 추가한다.

    <DragDropContext>
      <Droppable droppableId="todos">
        {(provided) => (
          <ul
            className="todos"
            {...provided.droppableProps}
            ref={provided.innerRef}
          >
            {todos.map(({ id, title }, index) => (
              <Draggable key={id} draggableId={id} index={index}>
                {(provided) => (
                  <li
                    ref={provided.innerRef}
                    {...provided.dragHandleProps}
                    {...provided.draggableProps}
                  >
                    {title}
                  </li>
                )}
              </Draggable>
            ))}
            {provided.placeholder}
          </ul>
        )}
      </Droppable>
    </DragDropContext>

이제 DND는 잘구현되지만 Drop된후의 상태가 저장안된다.

이걸구현해보자.

Drop후 상태저장

useState를써서 state로 상태를 변경하고
DragDropContext에 props으로 onDragEnd를 준다.
<DragDropContext onDragEnd={handleChange}>

이함수를 구현해서 인자로받는 녀석 콘솔찍어보면 DND에대한 여러 결과들이 나온다.
이를통해서 setState하면된다.

  const handleChange = (result) => {
    if (!result.destination) return;
    console.log(result);
    const items = [...todos];
    const [reorderedItem] = items.splice(result.source.index, 1);
    items.splice(result.destination.index, 0, reorderedItem);

    setTodos(items);
  };

예시 코드

도움받은 곳: https://www.freecodecamp.org/news/how-to-add-drag-and-drop-in-react-with-react-beautiful-dnd/

다양한 예제 : https://codesandbox.io/examples/package/react-beautiful-dnd

1개의 댓글

comment-user-thumbnail
2021년 12월 27일

파라마티로 꼭 ({id,title},index) 이렇게만 전달가능한가요 ?
배열안에 있는 각 오브젝트를 item이란 인자로 쓸 순 없나요 ?

답글 달기