react-beautiful-dnd
라이브러리 사용하기로 결정그럼 시작해보자.
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를 적용하고싶은 곳에 래핑한다.
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들을 추가해준다.
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된후의 상태가 저장안된다.
이걸구현해보자.
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
파라마티로 꼭 ({id,title},index) 이렇게만 전달가능한가요 ?
배열안에 있는 각 오브젝트를 item이란 인자로 쓸 순 없나요 ?