[React, Next.js] react-beautiful-dnd를 사용하여 드래그로 순서 변경하기
본문 바로가기
더 알아보기/기능

[React, Next.js] react-beautiful-dnd를 사용하여 드래그로 순서 변경하기

by 은돌1113 2022. 6. 28.

라이브러리는 react-beautiful-dnd npm 사이트에서 가져와서 사용했다.

 

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 1288 other projects in the npm registry using

www.npmjs.com

npm i react-beautiful-dnd

첫 번째 시도

 

react-beautiful-dnd

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

velog.io

 

프로젝트 진행 중에 멀티 이미지를 업로드하고 드래그 앤 드롭으로 이미지 순서를 변경할 수 있는 기능을 만들게 되어 찾아보던 중 위 블로그를 보게 되었고 적용했을 때 아래 사진과 같이 console에 오류가 발생하여 적용하지 못했다.


두 번째 시도

해결책을 찾지 못해 이번에는 키워드를 Next.js 이미지 순서 변경이라고 검색해서 아래 블로그를 발견했다.

 

[react-beautiful-dnd] react, next.js 드래그 만들기 3

[react-beautiful-dnd] react, next.js 드래그 만들기 2 [react-beautiful-dnd] react, next.js 드래그 만들기 2 [react-beautiful-dnd] react, next.js 드래그 만들기 1 [react-beautiful-dnd] react, next.js 드..

minaminaworld.tistory.com

 

이 블로그에서는 처음에 봤던 블로그와 달리 DragLand라는 컴포넌트에서 useEffect를 사용하여 컴포넌트가 생성된 후 Drag 컴포넌트를 호출하는 방법을 사용하셨다. 결과는 성공적이었다.


문제 해결

그때 문득 의문이 생겼다.

첫 번째 블로그와 두 번째 블로그를 비교해 봤을 때 크게 다른 부분은 useEffect의 사용 유무였다.

첫 번째 블로그 예제에 DragLand 코드를 적용해 보니 문제점이 해결되었다.

결국 컴포넌트가 생성되기 전에 라이브러리가 호출되어서 발생한 문제였던 것 같다.


두 개의 코드를 적절히 섞어 보았다.

더보기
// React 관련 요소
import { useEffect, useState } from "react";

// 드래그 요소
import { DragDropContext, Draggable, Droppable } from "react-beautiful-dnd";
// 스타일 정의
import styled from "styled-components";

const DragContent = styled.div`
  border: 1px solid lightgrey;
`;

const DragLand = () => {
  // window가 로드 된 시점에서 렌더링
  const [winReady, setwinReady] = useState(false);

  useEffect(() => {
    setwinReady(true);
  }, []);

  return (
    <>
      {/* 윈도우, DOM 로드 시점에서 드래그 생성 */}
      {winReady ? <Drag /> : null}
    </>
  );
};

// 드래그 요소 생성
export const Drag = () => {
  const [todos, setTodos] = useState([
    { id: "1", title: "공부" },
    { id: "2", title: "헬스" },
    { id: "3", title: "독서" },
    { id: "4", title: "산책" },
    { id: "5", title: "요리" },
  ]);

  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);
  };

  return (
    <>
      {/* 드래그 영역 */}
      <DragDropContext onDragEnd={handleChange}>
        {/* 드래그 놓을 수 있는 영역 */}
        <Droppable droppableId="DropLand">
          {/* 드래그 Div 생성 */}
          {(provided, snapshot) => (
            // CCS가 적용된 Div
            <DragContent {...provided.droppableProps} ref={provided.innerRef}>
              {todos.map((data, index) => (
                <Draggable key={data.id} draggableId={data.id} index={index}>
                  {(provided, snapshot) => (
                    <Content
                      ref={provided.innerRef}
                      {...provided.draggableProps}
                      {...provided.dragHandleProps}
                    >
                      {data.title}
                    </Content>
                  )}
                </Draggable>
              ))}
              {provided.placeholder}
            </DragContent>
          )}
        </Droppable>
      </DragDropContext>
    </>
  );
};

const Content = styled.div`
  margin: 8px;
  padding: 10px;
  border: 1px solid lightgrey;
  background: aliceblue;
  border-radius: 2px;
`;

export default DragLand;

 

+ 2023.02.07 - 특정 부분만 드래그 가능하도록 하는 방법

위에서 구현했던 기능에서는 박스 전체에서 드래그로 순서 변경이 가능했기 때문에

추가로 특정 부분을 드래그했을 때만 박스 순서를 변경할 수 있는 기능을 구현하고 싶었다.

 

많은 시행착오가 있었지만... 마음을 다잡고 천천히 해보니 쉽게 해결 가능한 부분이었다.

 

위에서 구현했던 코드를 살펴보면

 

Draggable이 드래그할 박스들의 영역이고, children에 div 태그에는 ref와 draggableProps, dragHandleProps가 있어서 이 부분을 중점적으로 보았을 때 dragHandlerProps는 드래그 기능을 담당하는 부분인 것 같고 draggableProps는 드래그로 순서 이동 했을 때 해당 값들을 담고 있지 않을까.. 생각이 들어서

 

 

아래처럼 {.. provided.dragHandleProps}를 div 태그에서 p 태그로 옮겨주었다. ☺️👍

 

댓글