치춘짱베리굿나이스

React-Beautiful-Dnd 본문

ClientSide/라이브러리

React-Beautiful-Dnd

치춘 2022. 5. 15. 12:03

React-beautiful-dnd

설치

$> npm i react-beautiful-dnd
$> yarn add react-beautiful-dnd

npm 링크

https://www.npmjs.com/package/react-beautiful-dnd

 

react-beautiful-dnd

Beautiful and accessible drag and drop for lists with React. Latest version: 13.1.0, last published: a year ago. Start using react-beautiful-dnd in your project by running `npm i react-beautiful-dnd`. There are 1265 other projects in the npm registry using

www.npmjs.com

yarn 링크

Contributors

 

https://yarnpkg.com/package/react-beautiful-dnd

Fast, reliable, and secure dependency management.

yarnpkg.com

용례

드래그 앤 드롭 리스트를 손쉽게 구현가능한 라이브러리이다

react-dnd는 사용자가 크기변경, 디자인, 애니메이션 등 세세한 부분의 커스터마이징이 가능한 대신 조금 복잡하고, 이번 과제에서는 일반적인 드래그 앤 드롭 순서변경만 구현하면 되기 때문에 커스터마이징 요소는 적은 대신 설정이 간편한 react-beautiful-dnd를 택하게 되었다

드래그 앤 드롭을 onDragEnd 이벤트로 사용할 수 있게끔 해주기 때문에, 여타 기본 이벤트 (onClick, onSubmit 등) 처럼 이벤트 핸들러를 추가해서 드래그 앤 드롭 이벤트를 제어할 수 있다

다만 단점은... 업데이트가 1년 전에 멈춰서 리액트 18버전을 사용하는 시점에 조만간 지원이 되지 않을 수도 있다는 것이다

fork 떠서 마저 업데이트를 진행하는 사람들이 있나 검색해봤는데 찾을 수 없었다

예시

<div className={styles.favoriteContainer}>
    <ul>
        {favoriteData.Movies.map((v: IMovie) => (
            <li key={`fav-list-${v.imdbID}`}>
                <MovieBlock movieData={v} />
            </li>
        ))}
    </ul>
</div>

ul + li 태그로 만든 간단한 리스트를 드래그 앤 드롭 리스트로 만들어줄 것이다

1. 드래그 앤 드롭 이벤트를 발생시킬 요소를 컨텍스트로 감싸주기

<div className={styles.favoriteContainer}>
    <DragDropContext onDragEnd={handleDragEnd}>
        <ul>
            {favoriteData.Movies.map((v: IMovie) => (
                <li key={`fav-list-${v.imdbID}`}>
                    <MovieBlock movieData={v} />
                </li>
            ))}
        </ul>
    </DragDropContext>
</div>

드래그 앤 드롭을 적용하고자 하는 리스트를 DragDropContext로 감싸 준다

div는 리스트의 배경을 담당하는 태그이기 때문에 가장 최상위로 빼내고, ul 리스트부터 감싸주었다

DragDropContextonDragEnd 이벤트 핸들러 함수를 props로 받는다

이 핸들러는 나중에 추가하도록 하자

2. 아이템 드롭이 이루어지는 컴포넌트를 Droppable로 감싸주기

<div className={styles.favoriteContainer}>
    <DragDropContext onDragEnd={handleDragEnd}>
        <Droppable droppableId='favoriteData'> {(droppableProv) => (
            <ul className={styles.favoriteUL} {...droppableProv.droppableProps} ref={droppableProv.innerRef}>
                {favoriteData.Movies.map((v: IMovie) => (
                    ...
                ))}
                {droppableProv.placeholder}
            </ul>)}
        </Droppable>
    </DragDropContext>
</div>

내부의 li가 드래그되는 요소이고, ul이 리스트의 바깥에서 드롭을 감지하므로, ulDroppable 컴포넌트로 감싸준다

droppableID는 고유값으로 지정해주고, ul을 화살표 함수로 한번 더 감싸준다

화살표 함수의 인자 droppableProv에는 드롭을 구현하기 위한 props들 (droppableProv.droppableProps)이 들어있으므로, 전개연산자를 통해 ul 태그에 props를 전달해주자

 

dnd 라이브러리가 ul 태그를 찾아 레퍼런스로 삼을 수 있도록 (내부 useRef) ref에 droppableProv.innerRef를 전달한다

ul 태그 내부의 끝에는 droppableProv.placeholder를 추가하여 드롭 컴포넌트의 끝임을 명시한다

ul 컴포넌트가 점점 복잡해지고 있는 것은 기분탓이다

3. 아이템 드래그가 이루어지는 컴포넌트를 Draggable로 감싸주기

...
{favoriteData.Movies.map((v: IMovie, i: number) => (
    <Draggable key={`fav-list-${v.imdbID}`} draggableId={`fav-list-${v.imdbID}`} index={i}>
        {(DraggableProv) => (
            <li
                ref={DraggableProv.innerRef}
                {...DraggableProv.dragHandleProps}
                {...DraggableProv.draggableProps}
            >
                <MovieBlock movieData={v} />
            </li>
        )}
    </Draggable>
))}
...

컴포넌트가 너무 복잡해져 map 함수로 리스트 요소들 (li) 을 렌더링하는 부분만 잘라왔다

우리는 li 요소의 드래그로 이벤트가 발생되기를 원하기 때문에, li 요소를 Draggable 컴포넌트로 감싸준다

Droppable과 비슷하게, draggableID는 고유 id값을 넣어주면 되고, 인덱스를 지정해주어야 한다

이 id값 덕분에 드롭 박스에서 어떤 요소가 드래그되었는지 인식하고, 인덱스를 지정하면 onDragEnd 이벤트 핸들러에서 어떤 인덱스의 요소가 어떤 인덱스로 이동했는지 정보를 인자로 보내주기 때문이다

 

Droppable 처럼 li 요소를 화살표 함수로 한번 감싸주고, li 요소에 드래그를 구현하기 위한 props를 전개연산자로 전달해 주었다 (DraggableProv.dragHandlePropsDraggableProv.draggableProps)

draggableProps는 드래그 시 애니메이션 등 스타일 적용을 위한 props들이 들어있고, dragHandleProps는 드래그 이벤트 발생 여부, 이벤트가 발생한 인덱스 등의 제어를 위한 props들이 들어있다 (궁금해서 한번 까봤다)

4. onDragEnd 핸들러 구성하기

const handleDragEnd = (r: DropResult) => {
    //
}

DragEnd 핸들러는 DropResult 타입의 인자를 하나 받는다

DropResult 인자 안에는 어떤 드래그 요소에서 이벤트가 발생했고, 해당 드래그 요소의 인덱스, 드롭했을 때 도착 지점의 인덱스 등을 담고 있다

핸들러 함수를 작성하려면 인자로 뭐가 들어오는지 알아야 하니 한번 출력해보자

source는 드래그한 요소의 정보를 담고 있으며, 위의 예시에서는 ID가 favoriteData인 드롭 박스 안에서 인덱스 1번의 요소를 드래그했음을 알 수 있다

destination은 드래그한 요소가 드롭되었을 때 도착지점의 정보를 담고 있으며, 예시에서는 fav-list-tt0366548이라는 ID의 요소가 0번 인덱스로 드롭되었음을 알 수 있다

드래그 앤 드롭 이벤트의 최종 목표는 거의 대부분 드래그한 요소의 순서를 바꾸는 것이므로, 핸들러 함수 내에서 이 r.source.indexr.destination.index를 이용하여 배열을 조작하면 된다

최종 결과물

핸들러 함수에서 드롭한 요소의 순서를 바꾸어주었으며, 덕분에 순서변경이 일어나 드롭한 위치에 요소가 고정되는 것을 볼 수 있다

참고자료

https://github.com/atlassian/react-beautiful-dnd

 

GitHub - atlassian/react-beautiful-dnd: Beautiful and accessible drag and drop for lists with React

Beautiful and accessible drag and drop for lists with React - GitHub - atlassian/react-beautiful-dnd: Beautiful and accessible drag and drop for lists with React

github.com

https://velog.io/@yjs3819/react-beautiful-dnd

 

react-beautiful-dnd

side project로 진행하는 todolist들을 drag and drop으로 카드를 재구성할수 있게 하고싶었다.react-dnd, 커스텀하게 직접 dnd를 구현.. 등등 여러방면으로 고민을하면서 codesandbox에서 실습을했는데 너무 어

velog.io

 

'ClientSide > 라이브러리' 카테고리의 다른 글

react-query 1. useQuery  (0) 2022.05.20
gh-pages로 리액트 프로젝트 배포 + 404 에러처리  (1) 2022.05.15
lodash  (0) 2022.05.14
store  (0) 2022.05.12
classnames  (0) 2022.05.06
Comments